Ticket #9294: 0003-Add-SSA-ASS-subtitle-support-libass.patch

File 0003-Add-SSA-ASS-subtitle-support-libass.patch, 12.2 KB (added by slackerlinux85@…, 13 years ago)

SSa subtitles using libass

  • mythtv/libs/libmythtv/avformatdecoder.cpp

    From d79359d6da910fc18e2523f6446068555b643a3e Mon Sep 17 00:00:00 2001
    From: shawn king <slackerlinux85@gmail.com>
    Date: Fri, 7 Jan 2011 13:17:36 +1000
    Subject: [PATCH 3/3] Add SSA/ASS subtitle support(libass)
    
    ---
     mythtv/libs/libmythtv/avformatdecoder.cpp |    5 +-
     mythtv/libs/libmythtv/libmythtv.pro       |    1 +
     mythtv/libs/libmythtv/subtitlescreen.cpp  |  245 ++++++++++++++++++++++++++++-
     mythtv/libs/libmythtv/subtitlescreen.h    |   22 +++
     4 files changed, 269 insertions(+), 4 deletions(-)
    
    diff --git a/mythtv/libs/libmythtv/avformatdecoder.cpp b/mythtv/libs/libmythtv/avformatdecoder.cpp
    index 4a0a0b6..dafcaee 100644
    a b int AvFormatDecoder::ScanStreams(bool novideo) 
    18731873            enc->codec_type != CODEC_TYPE_SUBTITLE)
    18741874            continue;
    18751875
    1876         // skip DVB teletext, text and SSA subs, there is no libavcodec decoder
     1876        // skip DVB teletext and text subs, there is no libavcodec decoder
    18771877        if (enc->codec_type == CODEC_TYPE_SUBTITLE &&
    18781878           (enc->codec_id   == CODEC_ID_DVB_TELETEXT ||
    1879             enc->codec_id   == CODEC_ID_TEXT ||
    1880             enc->codec_id   == CODEC_ID_SSA))
     1879            enc->codec_id   == CODEC_ID_TEXT))
    18811880            continue;
    18821881
    18831882        VERBOSE(VB_PLAYBACK, LOC + QString("Looking for decoder for %1")
  • mythtv/libs/libmythtv/libmythtv.pro

    diff --git a/mythtv/libs/libmythtv/libmythtv.pro b/mythtv/libs/libmythtv/libmythtv.pro
    index 59c4593..10a9366 100644
    a b LIBS += -lmythavformat 
    5656LIBS += -lmythavcodec
    5757LIBS += -lmythavcore
    5858LIBS += -lmythavutil
     59LIBS += -lass
    5960LIBS += -lmythui-$$LIBVERSION       -lmythupnp-$$LIBVERSION
    6061LIBS += -lmythdvdnav-$$LIBVERSION
    6162LIBS += -lmythbluray-$$LIBVERSION    -lmythdb-$$LIBVERSION
  • mythtv/libs/libmythtv/subtitlescreen.cpp

    diff --git a/mythtv/libs/libmythtv/subtitlescreen.cpp b/mythtv/libs/libmythtv/subtitlescreen.cpp
    index bbef05b..1b3817e 100644
    a b SubtitleScreen::SubtitleScreen(MythPlayer *player, const char * name, 
    2323    m_708reader(NULL), m_safeArea(QRect()), m_useBackground(false),
    2424    m_removeHTML(QRegExp("</?.+>")),        m_subtitleType(kDisplayNone),
    2525    m_textFontZoom(100),                    m_refreshArea(false),
    26     m_fontStretch(fontStretch)
     26    m_fontStretch(fontStretch),             m_assLibrary(NULL),
     27    m_assRenderer(NULL),                    m_asstracknum(-1),
     28    m_assTrack(NULL),                       m_assScreenRect(QRect())
    2729{
    2830    m_708fontSizes[0] = 36;
    2931    m_708fontSizes[1] = 45;
    3032    m_708fontSizes[2] = 60;
    3133    m_removeHTML.setMinimal(true);
     34    InitialiseAssLibrary();
    3235}
    3336
    3437SubtitleScreen::~SubtitleScreen(void)
    3538{
    3639    ClearAllSubtitles();
     40    CleanupAssLibrary();
    3741}
    3842
    3943void SubtitleScreen::EnableSubtitles(int type)
    void SubtitleScreen::ClearAllSubtitles(void) 
    9599{
    96100    ClearNonDisplayedSubtitles();
    97101    ClearDisplayedSubtitles();
     102    if (m_assTrack)
     103        ass_flush_events(m_assTrack);
    98104}
    99105
    100106void SubtitleScreen::ClearNonDisplayedSubtitles(void)
    void SubtitleScreen::DisplayAVSubtitles(void) 
    291297                            QString("AV Sub was %1 ms late").arg(late));
    292298                }
    293299            }
     300            else if (displaysub && rect->type == SUBTITLE_ASS)
     301            {
     302                InitialiseAssTrack(m_player->GetDecoder()->GetTrack(kTrackTypeSubtitle));
     303                AddAssEvent(rect->ass);
     304            }
    294305        }
    295306        m_subreader->FreeAVSubtitle(subtitle);
    296307    }
     308    RenderASSTrack(currentFrame->timecode);
    297309    subs->lock.unlock();
    298310}
    299311
    MythFontProperties* SubtitleScreen::Get708Font(CC708CharacterAttribute attr) 
    10221034
    10231035    return mythfont;
    10241036}
     1037
     1038/* Mostly copied from avformatdecoder */
     1039static void myth_libass_log(int level, const char *fmt, va_list vl, void *ctx)
     1040{
     1041    static QString full_line("LibASS:");
     1042    static const int msg_len = 255;
     1043    static QMutex string_lock;
     1044    uint verbose_level = 0;
     1045
     1046    switch (level)
     1047    {
     1048        case 0: //MSGL_FATAL
     1049            verbose_level = VB_IMPORTANT;
     1050            break;
     1051        case 1: //MSGL_ERR
     1052        case 2: //MSGL_WARN
     1053        case 4: //MSGL_INFO
     1054            verbose_level = VB_GENERAL;
     1055            break;
     1056        case 6: //MSGL_V
     1057        case 7: //MSGL_DBG2
     1058        default:
     1059            return;
     1060    }
     1061
     1062    if (!VERBOSE_LEVEL_CHECK(verbose_level))
     1063        return;
     1064
     1065    string_lock.lock();
     1066
     1067    char str[msg_len+1];
     1068    int bytes = vsnprintf(str, msg_len+1, fmt, vl);
     1069    // check for truncated messages and fix them
     1070    if (bytes > msg_len)
     1071    {
     1072        VERBOSE(VB_IMPORTANT, QString("libASS log output truncated %1 of %2 bytes written")
     1073                .arg(msg_len).arg(bytes));
     1074        str[msg_len-1] = '\n';
     1075    }
     1076
     1077    full_line += QString(str);
     1078    if (full_line.endsWith("\n"))
     1079    {
     1080        full_line.truncate(full_line.length() - 1);
     1081        VERBOSE(verbose_level, full_line);
     1082        full_line.truncate(0);
     1083    }
     1084    string_lock.unlock();
     1085}
     1086
     1087void SubtitleScreen::InitialiseAssLibrary(void)
     1088{
     1089    m_assLibrary = ass_library_init();
     1090    ass_set_message_cb(m_assLibrary, myth_libass_log, NULL);
     1091    ass_set_extract_fonts(m_assLibrary, true);
     1092    //add embedded fonts
     1093    for ( uint i = 0; i < m_player->GetDecoder()->GetTrackCount(kTrackTypeAttachment); ++i)
     1094    {
     1095        QByteArray filename;
     1096        QByteArray font;
     1097
     1098        m_player->GetDecoder()->GetAttachmentData(i, filename, font);
     1099        ass_add_font(m_assLibrary, filename.data(), font.data(), font.size());
     1100    }
     1101
     1102    m_assRenderer = ass_renderer_init(m_assLibrary);
     1103    if (!m_assRenderer)
     1104        return;
     1105
     1106    ass_set_fonts(m_assRenderer, NULL, "sans-serif", 1, NULL, 1);
     1107    ass_set_hinting(m_assRenderer, ASS_HINTING_LIGHT);
     1108    VERBOSE(VB_PLAYBACK | VB_EXTRA, LOC + QString("libASS library Init"));
     1109}
     1110
     1111void SubtitleScreen::CleanupAssLibrary(void)
     1112{
     1113    CleanupAssTrack();
     1114    if (m_assRenderer)
     1115        ass_renderer_done(m_assRenderer);
     1116    m_assRenderer = NULL;
     1117    if (m_assLibrary)
     1118    {
     1119        ass_clear_fonts(m_assLibrary);
     1120        ass_library_done(m_assLibrary);
     1121    }
     1122    m_assLibrary = NULL;
     1123    VERBOSE(VB_PLAYBACK | VB_EXTRA, LOC + QString("libASS library cleanup"));
     1124}
     1125
     1126void SubtitleScreen::InitialiseAssTrack(int tracknum)
     1127{
     1128    if (tracknum == m_asstracknum && m_assTrack)
     1129        return;
     1130
     1131    CleanupAssTrack();
     1132    m_assTrack = ass_new_track(m_assLibrary);
     1133    m_asstracknum = tracknum;
     1134
     1135    QByteArray header = m_player->GetDecoder()->GetSubHeader(tracknum);
     1136    if (!header.isNull())
     1137    {
     1138        ass_process_codec_private(m_assTrack, header.data(), header.size());
     1139    }
     1140
     1141    float tmp = 0.0;
     1142    QRect dummy;
     1143    m_player->getVideoOutput()->GetOSDBounds(dummy, m_assScreenRect, tmp, tmp, tmp);
     1144    ResizeASSRenderer(m_assScreenRect);
     1145    VERBOSE(VB_PLAYBACK | VB_EXTRA, LOC + QString("libASS Track Init(%1)").arg(m_asstracknum));
     1146}
     1147
     1148void SubtitleScreen::CleanupAssTrack(void)
     1149{
     1150    if (m_assTrack)
     1151        ass_free_track(m_assTrack);
     1152    m_assTrack = NULL;
     1153    VERBOSE(VB_PLAYBACK | VB_EXTRA, LOC + QString("libASS Track cleanup"));
     1154}
     1155
     1156void SubtitleScreen::AddAssEvent(char *event)
     1157{
     1158    if (m_assTrack)
     1159    {
     1160        ass_process_data(m_assTrack, event, strlen(event));
     1161        VERBOSE(VB_PLAYBACK | VB_EXTRA, LOC + QString("libASS event added to track(%i): %1").arg(m_asstracknum).arg(event));
     1162    }
     1163}
     1164
     1165void SubtitleScreen::ResizeASSRenderer(const QRect &Screen)
     1166{
     1167    //int mt, mb, ml, mr;
     1168    ass_set_frame_size(m_assRenderer, Screen.width(), Screen.height());
     1169    ass_set_margins(m_assRenderer, 0, 0, 0, 0);
     1170    ass_set_use_margins(m_assRenderer, true);
     1171    ass_set_font_scale(m_assRenderer, 1.0);
     1172}
     1173
     1174void SubtitleScreen::RenderASSTrack(uint64_t timecode)
     1175{
     1176    VideoOutput *vo = m_player->getVideoOutput();
     1177    ASS_Image *images = NULL;
     1178    int count = 0;
     1179    int changed = 0;
     1180
     1181    if (!vo || !m_assRenderer || !m_assTrack)
     1182        return;
     1183
     1184    QRect oldscreen = m_assScreenRect;
     1185    QRect dummy;
     1186    float tmp = 0.0;
     1187    vo->GetOSDBounds(dummy, m_assScreenRect, tmp, tmp, tmp);
     1188    if (oldscreen != m_assScreenRect)
     1189        ResizeASSRenderer(m_assScreenRect);
     1190
     1191    images = ass_render_frame(m_assRenderer, m_assTrack, timecode, &changed);
     1192    if (changed)
     1193    {
     1194        MythPainter *osd_painter = vo->GetOSDPainter();
     1195        if (!osd_painter)
     1196            return;
     1197        DeleteAllChildren();
     1198        SetRedraw();
     1199        while (images)
     1200        {
     1201            //if width or height = 0 then dont display this image
     1202            if (images->w == 0 || images->h == 0)
     1203            {
     1204                images = images->next;
     1205                continue;
     1206            }
     1207
     1208            uint8_t alpha = images->color & 0xFF;
     1209            uint8_t blue = images->color >> 8 & 0xFF;
     1210            uint8_t green = images->color >> 16 & 0xFF;
     1211            uint8_t red = images->color >> 24 & 0xFF;
     1212
     1213            //image is fully transparent dont need to render
     1214            if (alpha == 255)
     1215            {
     1216                images = images->next;
     1217                continue;
     1218            }
     1219
     1220            QSize ImageSize(images->w, images->h);
     1221            QRect DisplayRect(images->dst_x, images->dst_y, images->w, images->h);
     1222
     1223            //create the image using Libass image data
     1224            QImage qImage(ImageSize, QImage::Format_ARGB32);
     1225            qImage.fill(0x00000000);
     1226
     1227            unsigned char *src = images->bitmap;
     1228            for (int y = 0; y < images->h; ++y)
     1229            {
     1230                for (int x = 0; x < images->w; ++x)
     1231                {
     1232                    uint8_t pixelvalue = src[x];
     1233                    if (pixelvalue)
     1234                    {
     1235                        uint8_t pixelalpha = pixelvalue * (255 - alpha) / 255;
     1236                        uint32_t pixel = (pixelalpha << 24) | (red << 16) | (green << 8) | (blue);
     1237                        qImage.setPixel(x, y, pixel);
     1238                    }
     1239                }
     1240                src += images->stride;
     1241            }
     1242
     1243            //add pictures to the OSD
     1244            MythImage* image = NULL;
     1245            MythUIImage *uiimage = NULL;
     1246
     1247            if (osd_painter)
     1248                image = osd_painter->GetFormatImage();
     1249
     1250            if (image)
     1251            {
     1252                image->Assign(qImage);
     1253                QString name = QString("asssub%1").arg(count);
     1254                uiimage = new MythUIImage(this, name);
     1255                if (uiimage)
     1256                {
     1257                        m_refreshArea = true;
     1258                        uiimage->SetImage(image);
     1259                        uiimage->SetArea(MythRect(DisplayRect));
     1260                }
     1261            }
     1262            images = images->next;
     1263            count++;
     1264        }
     1265        VERBOSE(VB_PLAYBACK | VB_EXTRA, LOC + QString("libASS Rendered %1 Images").arg(count));
     1266    }
     1267}
  • mythtv/libs/libmythtv/subtitlescreen.h

    diff --git a/mythtv/libs/libmythtv/subtitlescreen.h b/mythtv/libs/libmythtv/subtitlescreen.h
    index c3283a4..b82da77 100644
    a b  
    22#define SUBTITLESCREEN_H
    33
    44#include <QFont>
     5extern "C" {
     6#include <ass/ass.h>
     7}
    58
    69#include "mythscreentype.h"
    710#include "subtitlereader.h"
    class SubtitleScreen : public MythScreenType 
    4447                           float aspect, vector<CC708String*> &list);
    4548    MythFontProperties* Get708Font(CC708CharacterAttribute attr);
    4649
     50    //LibASS additions
     51    void InitialiseAssLibrary(void);
     52    void CleanupAssLibrary(void);
     53
     54    void InitialiseAssTrack(int tracknum);
     55    void CleanupAssTrack(void);
     56
     57    void AddAssEvent(char *event);
     58
     59    void ResizeASSRenderer(const QRect &Screen);
     60    void RenderASSTrack(uint64_t timecode);
     61
    4762    MythPlayer *m_player;
    4863    SubtitleReader    *m_subreader;
    4964    CC608Reader       *m_608reader;
    class SubtitleScreen : public MythScreenType 
    5873    bool               m_refreshArea;
    5974    QHash<int,QList<MythUIType*> > m_708imageCache;
    6075    int                m_fontStretch;
     76
     77    //LibASS additions
     78    ASS_Library       *m_assLibrary;
     79    ASS_Renderer      *m_assRenderer;
     80    int                m_asstracknum;
     81    ASS_Track         *m_assTrack;
     82    QRect              m_assScreenRect;
    6183};
    6284
    6385#endif // SUBTITLESCREEN_H