Ticket #30: dvbsub_display_code.patch

File dvbsub_display_code.patch, 13.9 KB (added by Pekka Jääskeläinen <pekka.jaaskelainen@…>, 19 years ago)

Displays subtitles decoded by the new ffmpeg DVB decoder.

  • libs/libmythtv/NuppelVideoPlayer.h

     
    3030class FilterManager;
    3131class FilterChain;
    3232class VideoSync;
     33struct AVSubtitle;
    3334
    3435struct TextContainer
    3536{
     
    223224        return 0;
    224225    }
    225226
     227    void DisplaySubtitles();
     228    void ClearSubtitles();
     229    void AddSubtitles(const AVSubtitle& subtitle);
     230    bool SubtitlesEnabled();
     231   
    226232 protected:
    227233    void DisplayPauseFrame(void);
    228234    void DisplayNormalFrame(void);
     
    483489
    484490    bool errored;
    485491
     492    // the key is the start display time in ms
     493    typedef QMap<uint32_t, AVSubtitle> SubtitleMap;
     494    SubtitleMap nondisplayedSubtitles;
     495    QMutex subtitleLock;
     496    bool osdHasSubtitles;
     497
    486498    int m_DeintSetting;
    487499};
    488500
  • libs/libmythtv/NuppelVideoPlayer.cpp

     
    207207
    208208    errored = false;
    209209    audio_timecode_offset = 0;
     210
     211    osdHasSubtitles = false;
    210212}
    211213
    212214NuppelVideoPlayer::~NuppelVideoPlayer(void)
     
    218220        delete m_playbackinfo;
    219221    if (weMadeBuffer)
    220222        delete ringBuffer;
     223
     224    ClearSubtitles();
     225
    221226    if (osd)
    222227        delete osd;
    223228   
     
    241246
    242247    if (videosync)
    243248        delete videosync;
     249
    244250}
    245251
    246252void NuppelVideoPlayer::SetWatchingRecording(bool mode)
     
    932938    QString msg;
    933939
    934940    vbimode = mode;
    935     if (cc && !arg)
     941
     942    if (cc && !arg)
    936943    {
    937944        cc = false;
    938945        ResetCC();
    939946        if (mode == 1)
    940947            msg = QObject::tr("TXT off");
    941         else
     948        else if (mode == 2)
    942949            msg = QObject::tr("CC off");
     950        else
     951            msg = QObject::tr("Subtitles off");
    943952    }
    944953    else
    945954    {
     
    9961005                break;
    9971006            }
    9981007        }
    999         else
    1000             msg = QString(QObject::tr("CC/TXT disabled"));
     1008        else 
     1009            msg = QString(QObject::tr("Subtitles on"));
    10011010    }
    10021011
    10031012    if (osd)
     
    15881597
    15891598    VideoFrame *frame = videoOutput->GetLastShownFrame();
    15901599
    1591     if (cc)
     1600    if (cc) {
    15921601        ShowText();
     1602        DisplaySubtitles();
     1603    } else {
     1604        ClearSubtitles();
     1605    }
    15931606
    15941607    videofiltersLock.lock();
    15951608    videoOutput->ProcessFrame(frame, osd, videoFilters, pipplayer);
     
    41024115        return false;
    41034116}
    41044117
    4105 
    41064118int NuppelVideoPlayer::getCurrentAudioTrack()
    41074119{
    41084120    if (decoder)
     
    41114123        return 0;
    41124124}
    41134125
     4126// updates new subtitles to the screen and clears old ones
     4127void NuppelVideoPlayer::DisplaySubtitles()
     4128{
     4129    OSDSet *subtitleOSD = NULL;
     4130    VideoFrame* currentFrame = videoOutput->GetLastShownFrame();
     4131    subtitleLock.lock();
     4132    SubtitleMap::iterator i1 = nondisplayedSubtitles.begin();
     4133    bool setVisible = false;
     4134
     4135    // time when the last shown subtitles should be hidden
     4136    static long long expireAt = -1;
     4137    static long long lastSubShownAt = -1;
     4138   
     4139    subtitleOSD = osd->GetSet("subtitles");
     4140   
     4141    // hide the subs if they have been long enough in the screen without
     4142    // new subtitles replacing them
     4143    if (osdHasSubtitles && currentFrame->timecode >= expireAt) {
     4144
     4145        osd->HideSet("subtitles");
     4146        VERBOSE(VB_PLAYBACK,
     4147                QString("Clearing expired subtitles from OSD set. Age was %1").
     4148                arg(currentFrame->timecode - lastSubShownAt));
     4149        osd->ClearAll("subtitles");
     4150        osdHasSubtitles = false;
     4151    }
     4152
     4153    while ((i1 != nondisplayedSubtitles.end()) &&
     4154           (i1.key() <= currentFrame->timecode))
     4155    {
     4156        const AVSubtitle& subtitlePage = i1.data();
     4157
     4158        // clear old subtitles
     4159        if (osdHasSubtitles) {
     4160            osd->HideSet("subtitles");
     4161            osd->ClearAll("subtitles");
     4162            osdHasSubtitles = false;
     4163        }
     4164        // draw the subtitle bitmap(s) to the OSD
     4165        for (std::size_t i = 0; i < subtitlePage.num_rects; ++i) {
     4166            AVSubtitleRect* rect = &subtitlePage.rects[i];
     4167            // because the buffer from rect might not start at 4 byte boundary,
     4168            // or at least each line won't, we'll have to create the QImage
     4169            // this way, one pixel at a time, as we cannot feed in the buffer
     4170            // directly
     4171            QImage qImage(rect->w, rect->h, 32);
     4172            qImage.setAlphaBuffer(true);
     4173            for (int y = 0; y < rect->h; ++y) {
     4174                for (int x = 0; x < rect->w; ++x) {
     4175                    const uint8_t color = rect->bitmap[y*rect->w + x];
     4176                    const uint32_t pixel = rect->rgba_palette[color];
     4177                    qImage.setPixel(x, y, pixel);
     4178                }
     4179            }
     4180            OSDTypeImage* image = new OSDTypeImage();
     4181            QPoint position(rect->x, rect->y);
     4182            image->SetPosition(position);
     4183            image->LoadFromQImage(qImage);
     4184            subtitleOSD->AddType(image);
     4185            av_free(rect->rgba_palette);
     4186            av_free(rect->bitmap);
     4187            setVisible = true;
     4188            osdHasSubtitles = true;
     4189        }
     4190        if (subtitlePage.num_rects > 0)
     4191            av_free(subtitlePage.rects);
     4192        expireAt = subtitlePage.end_display_time;
     4193        lastSubShownAt = currentFrame->timecode;
     4194
     4195        // the iterator is not guaranteed to point to anything sensible
     4196        // after the erase() call, thus we have to save the next iterator
     4197        // before erasing
     4198        SubtitleMap::iterator nextSub = i1;
     4199        ++nextSub;
     4200        nondisplayedSubtitles.erase(i1);       
     4201        i1 = nextSub;
     4202    }
     4203    subtitleLock.unlock();
     4204
     4205    if (setVisible)
     4206    {
     4207        VERBOSE(
     4208            VB_PLAYBACK,
     4209            QString("Setting subtitles visible, frame_timecode=%1")
     4210            .arg(currentFrame->timecode));
     4211        osd->SetVisible(subtitleOSD, 0);
     4212    }
     4213}
     4214
     4215// hide subtitles and free the undisplayed subtitles
     4216void NuppelVideoPlayer::ClearSubtitles() {
     4217    OSDSet* osdSet = 0;
     4218
     4219    subtitleLock.lock();
     4220    if (nondisplayedSubtitles.size() > 0) {
     4221
     4222        // Delete all non-displayed held subtitles
     4223        for (SubtitleMap::iterator i1 = nondisplayedSubtitles.begin();
     4224             i1 != nondisplayedSubtitles.end(); )
     4225        {
     4226
     4227            AVSubtitle& subtitle = i1.data();
     4228   
     4229            // Because the subtitles were not displayed, OSDSet does not
     4230            // free the OSDTypeImages in ClearAll(), so we have to free
     4231            // the dynamic buffers here
     4232            for (std::size_t i = 0; i < subtitle.num_rects; ++i) {
     4233                AVSubtitleRect* rect = &subtitle.rects[i];
     4234                av_free(rect->rgba_palette);
     4235                av_free(rect->bitmap);
     4236            }
     4237
     4238            SubtitleMap::iterator nexti1 = i1;
     4239            ++nexti1;
     4240
     4241            nondisplayedSubtitles.erase( i1 );
     4242            i1 = nexti1;
     4243        }
     4244    }
     4245    subtitleLock.unlock();
     4246
     4247    // Clear subtitles from OSD
     4248    if (osdHasSubtitles && osd)
     4249        osdSet = osd->GetSet("subtitles");
     4250
     4251    if( osdSet )
     4252    {
     4253        osd->HideSet("subtitles");
     4254        osdSet->Clear();
     4255        osdHasSubtitles = false;
     4256    }
     4257}
     4258
     4259bool NuppelVideoPlayer::SubtitlesEnabled() {
     4260    return cc;
     4261}
     4262// adds a new subtitle to be shown
     4263void NuppelVideoPlayer::AddSubtitles(const AVSubtitle& subtitle) {
     4264    nondisplayedSubtitles[subtitle.start_display_time] = subtitle;
     4265}
  • libs/libmythtv/osd.h

     
    4848
    4949    OSDSurface *Display(void);
    5050
     51    void ClearAll(const QString &name);
    5152    void ClearAllText(const QString &name);
    5253    void SetText(const QString &name, QMap<QString, QString> &infoMap,
    5354                         int length);
  • libs/libmythtv/avformatdecoder.cpp

     
    167167    firstgoppos = 0;
    168168    prevgoppos = 0;
    169169
     170    subtitleLanguagePreferences =
     171        QStringList::split(",", gContext->GetSetting("PreferredLanguages", ""));
     172
    170173    fps = 29.97;
    171174    maxkeyframedist = -1;
    172175
     
    191194    delete d;
    192195}
    193196
     197
     198// evaluates whether the given language is the subtitle language that is
     199// preferred
     200//
     201// in case there's only one subtitle language available, always returns true
     202//
     203// if more than one subtitle languages are found, the best one is
     204// picked according to the PreferredLanguages setting
     205//
     206// in case there's no PreferredLanguages setting, or no preferred language
     207// is found, the first found subtitle stream is preferred
     208bool AvFormatDecoder::IsWantedSubtitleLanguage(QString language) {
     209   
     210    if (!ic)
     211        return true;
     212
     213    // count the subtitle streams
     214    int subtitleStreams = 0;
     215    AVStream *first = NULL;
     216    for (int i = 0; i < ic->nb_streams; i++)
     217    {
     218        AVStream* st = ic->streams[i];
     219        if (st->codec.codec_type == CODEC_TYPE_SUBTITLE) {
     220            if (first == NULL)
     221                first = ic->streams[i];
     222            ++subtitleStreams;
     223        }
     224    }
     225    if (subtitleStreams == 1)
     226        return true;
     227   
     228    // go through all preferred languages and pick the best found
     229    for (QStringList::iterator l = subtitleLanguagePreferences.begin();
     230         l != subtitleLanguagePreferences.end(); ++l) {
     231
     232        for (int i = 0; i < ic->nb_streams; i++)
     233        {           
     234            AVStream* st = ic->streams[i];
     235
     236            if (st->language == *l) {
     237                return (language == st->language);
     238            }
     239        }
     240    }
     241    // no preferences at all, or no language that is preferred found --
     242    // let's pick the first subtitle stream
     243    return language == first->language;
     244}
     245
     246
    194247void AvFormatDecoder::CloseContext()
    195248{
    196249    if (ic)
     
    842895                bitrate += enc->bit_rate;
    843896                break;
    844897            }
     898            case CODEC_TYPE_SUBTITLE:
     899            {
     900                bitrate += enc->bit_rate;
     901                VERBOSE(VB_PLAYBACK,
     902                        QString("AvFormatDecoder: subtitle codec")
     903                        .arg(enc->codec_type));
     904                break;
     905            }
    845906            case CODEC_TYPE_DATA:
    846907            {
    847908                bitrate += enc->bit_rate;
     
    861922        }
    862923
    863924        if (enc->codec_type != CODEC_TYPE_AUDIO &&
    864             enc->codec_type != CODEC_TYPE_VIDEO)
     925            enc->codec_type != CODEC_TYPE_VIDEO &&
     926            enc->codec_type != CODEC_TYPE_SUBTITLE)
    865927            continue;
    866928
    867929        VERBOSE(VB_PLAYBACK, QString("AVFD: Looking for decoder for %1")
     
    16751737        if (!curstream->codec.codec)
    16761738        {
    16771739            VERBOSE(VB_PLAYBACK, QString("No codec for stream index %1").arg(pkt->stream_index));
    1678             av_free_packet(pkt);
     1740            av_free_packet(pkt);           
    16791741            continue;
    16801742        }
    16811743
     
    18481910                    lastvpts = temppts;
    18491911                    break;
    18501912                }
     1913                case CODEC_TYPE_SUBTITLE:
     1914                {
     1915                    AVCodecContext *context = &(curstream->codec);
     1916                    int gotSubtitles = 0;
     1917                    AVSubtitle subtitle;
     1918                   
     1919                    if (m_parent->SubtitlesEnabled() &&
     1920                        IsWantedSubtitleLanguage(curstream->language))
     1921                        avcodec_decode_subtitle(
     1922                            context, &subtitle, &gotSubtitles, ptr, len);
     1923                    // the subtitle decoder always consumes the whole packet
     1924                    ptr += len;
     1925                    len = 0;
     1926
     1927                    if (gotSubtitles) {
     1928                        subtitle.start_display_time += pts;
     1929                        subtitle.end_display_time += pts;
     1930                        m_parent->AddSubtitles(subtitle);
     1931                    }
     1932
     1933                    break;
     1934                }
    18511935                default:
    18521936                    cerr << "error decoding - " << curstream->codec.codec_type
    18531937                         << endl;
  • libs/libmythtv/avformatdecoder.h

     
    128128
    129129    // Update our position map, keyframe distance, and the like.  Called for key frame packets.
    130130    void HandleGopStart(AVPacket *pkt);
     131
     132    bool IsWantedSubtitleLanguage(QString language);
    131133   
    132134    class AvFormatDecoderPrivate *d;
    133135
     
    179181    MythCodecID video_codec_id;
    180182
    181183    int maxkeyframedist;
     184
     185    QStringList subtitleLanguagePreferences;
    182186};
    183187
    184188#endif
  • libs/libmythtv/osdtypes.cpp

     
    133133
    134134OSDSet::~OSDSet()
    135135{
    136     vector<OSDType *>::iterator i = allTypes->begin();
    137     for (; i != allTypes->end(); i++)
    138     {
    139         OSDType *type = (*i);
    140         if (type)
    141             delete type;
    142     }
     136    this->Clear();
    143137    delete allTypes;
    144138}
     139
     140void OSDSet::Clear()
     141{
     142     vector<OSDType *>::iterator i = allTypes->begin();
     143     for (; i != allTypes->end(); i++)
     144     {
     145         OSDType* type = *i;
     146         if (type)
     147             delete type;
     148     }
     149    allTypes->clear();
     150
     151}
    145152 
    146153void OSDSet::AddType(OSDType *type)
    147154{
  • libs/libmythtv/osdtypes.h

     
    2424           float wmult, float hmult, int frint);
    2525    OSDSet(const OSDSet &other);
    2626   ~OSDSet();
     27   
     28    void Clear();
    2729
    2830    void SetCache(bool cache) { m_cache = cache; }
    2931    bool GetCache() { return m_cache; }
  • libs/libmythtv/osd.cpp

     
    196196
    197197        container->AddType(lb);
    198198    }
     199
     200     
     201    // Create container for subtitles
     202    container = GetSet("subtitles");
     203    if (!container)
     204    {
     205        QString name = "subtitles";
     206        container = new OSDSet(name, true, vid_width, vid_height, wmult, hmult,
     207                               frameint);
     208        AddSet(container, name);
     209    }   
    199210}
    200211
    201212void OSD::Reinit(int width, int height, int frint, int dispx, int dispy,
     
    12241235    return retval;
    12251236}
    12261237
     1238void OSD::ClearAll(const QString &name)
     1239{
     1240    osdlock.lock();
     1241    OSDSet *container = GetSet(name);
     1242    if (container)
     1243        container->Clear();
     1244
     1245    osdlock.unlock();
     1246}
     1247
    12271248void OSD::ClearAllText(const QString &name)
    12281249{
    12291250    osdlock.lock();