Ticket #30: dvbsub_display_code.patch
File dvbsub_display_code.patch, 13.9 KB (added by , 19 years ago) |
---|
-
libs/libmythtv/NuppelVideoPlayer.h
30 30 class FilterManager; 31 31 class FilterChain; 32 32 class VideoSync; 33 struct AVSubtitle; 33 34 34 35 struct TextContainer 35 36 { … … 223 224 return 0; 224 225 } 225 226 227 void DisplaySubtitles(); 228 void ClearSubtitles(); 229 void AddSubtitles(const AVSubtitle& subtitle); 230 bool SubtitlesEnabled(); 231 226 232 protected: 227 233 void DisplayPauseFrame(void); 228 234 void DisplayNormalFrame(void); … … 483 489 484 490 bool errored; 485 491 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 486 498 int m_DeintSetting; 487 499 }; 488 500 -
libs/libmythtv/NuppelVideoPlayer.cpp
207 207 208 208 errored = false; 209 209 audio_timecode_offset = 0; 210 211 osdHasSubtitles = false; 210 212 } 211 213 212 214 NuppelVideoPlayer::~NuppelVideoPlayer(void) … … 218 220 delete m_playbackinfo; 219 221 if (weMadeBuffer) 220 222 delete ringBuffer; 223 224 ClearSubtitles(); 225 221 226 if (osd) 222 227 delete osd; 223 228 … … 241 246 242 247 if (videosync) 243 248 delete videosync; 249 244 250 } 245 251 246 252 void NuppelVideoPlayer::SetWatchingRecording(bool mode) … … 932 938 QString msg; 933 939 934 940 vbimode = mode; 935 if (cc && !arg) 941 942 if (cc && !arg) 936 943 { 937 944 cc = false; 938 945 ResetCC(); 939 946 if (mode == 1) 940 947 msg = QObject::tr("TXT off"); 941 else 948 else if (mode == 2) 942 949 msg = QObject::tr("CC off"); 950 else 951 msg = QObject::tr("Subtitles off"); 943 952 } 944 953 else 945 954 { … … 996 1005 break; 997 1006 } 998 1007 } 999 else 1000 msg = QString(QObject::tr("CC/TXT disabled"));1008 else 1009 msg = QString(QObject::tr("Subtitles on")); 1001 1010 } 1002 1011 1003 1012 if (osd) … … 1588 1597 1589 1598 VideoFrame *frame = videoOutput->GetLastShownFrame(); 1590 1599 1591 if (cc) 1600 if (cc) { 1592 1601 ShowText(); 1602 DisplaySubtitles(); 1603 } else { 1604 ClearSubtitles(); 1605 } 1593 1606 1594 1607 videofiltersLock.lock(); 1595 1608 videoOutput->ProcessFrame(frame, osd, videoFilters, pipplayer); … … 4102 4115 return false; 4103 4116 } 4104 4117 4105 4106 4118 int NuppelVideoPlayer::getCurrentAudioTrack() 4107 4119 { 4108 4120 if (decoder) … … 4111 4123 return 0; 4112 4124 } 4113 4125 4126 // updates new subtitles to the screen and clears old ones 4127 void 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 4216 void 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 4259 bool NuppelVideoPlayer::SubtitlesEnabled() { 4260 return cc; 4261 } 4262 // adds a new subtitle to be shown 4263 void NuppelVideoPlayer::AddSubtitles(const AVSubtitle& subtitle) { 4264 nondisplayedSubtitles[subtitle.start_display_time] = subtitle; 4265 } -
libs/libmythtv/osd.h
48 48 49 49 OSDSurface *Display(void); 50 50 51 void ClearAll(const QString &name); 51 52 void ClearAllText(const QString &name); 52 53 void SetText(const QString &name, QMap<QString, QString> &infoMap, 53 54 int length); -
libs/libmythtv/avformatdecoder.cpp
167 167 firstgoppos = 0; 168 168 prevgoppos = 0; 169 169 170 subtitleLanguagePreferences = 171 QStringList::split(",", gContext->GetSetting("PreferredLanguages", "")); 172 170 173 fps = 29.97; 171 174 maxkeyframedist = -1; 172 175 … … 191 194 delete d; 192 195 } 193 196 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 208 bool 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 194 247 void AvFormatDecoder::CloseContext() 195 248 { 196 249 if (ic) … … 842 895 bitrate += enc->bit_rate; 843 896 break; 844 897 } 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 } 845 906 case CODEC_TYPE_DATA: 846 907 { 847 908 bitrate += enc->bit_rate; … … 861 922 } 862 923 863 924 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) 865 927 continue; 866 928 867 929 VERBOSE(VB_PLAYBACK, QString("AVFD: Looking for decoder for %1") … … 1675 1737 if (!curstream->codec.codec) 1676 1738 { 1677 1739 VERBOSE(VB_PLAYBACK, QString("No codec for stream index %1").arg(pkt->stream_index)); 1678 av_free_packet(pkt); 1740 av_free_packet(pkt); 1679 1741 continue; 1680 1742 } 1681 1743 … … 1848 1910 lastvpts = temppts; 1849 1911 break; 1850 1912 } 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 } 1851 1935 default: 1852 1936 cerr << "error decoding - " << curstream->codec.codec_type 1853 1937 << endl; -
libs/libmythtv/avformatdecoder.h
128 128 129 129 // Update our position map, keyframe distance, and the like. Called for key frame packets. 130 130 void HandleGopStart(AVPacket *pkt); 131 132 bool IsWantedSubtitleLanguage(QString language); 131 133 132 134 class AvFormatDecoderPrivate *d; 133 135 … … 179 181 MythCodecID video_codec_id; 180 182 181 183 int maxkeyframedist; 184 185 QStringList subtitleLanguagePreferences; 182 186 }; 183 187 184 188 #endif -
libs/libmythtv/osdtypes.cpp
133 133 134 134 OSDSet::~OSDSet() 135 135 { 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(); 143 137 delete allTypes; 144 138 } 139 140 void 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 } 145 152 146 153 void OSDSet::AddType(OSDType *type) 147 154 { -
libs/libmythtv/osdtypes.h
24 24 float wmult, float hmult, int frint); 25 25 OSDSet(const OSDSet &other); 26 26 ~OSDSet(); 27 28 void Clear(); 27 29 28 30 void SetCache(bool cache) { m_cache = cache; } 29 31 bool GetCache() { return m_cache; } -
libs/libmythtv/osd.cpp
196 196 197 197 container->AddType(lb); 198 198 } 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 } 199 210 } 200 211 201 212 void OSD::Reinit(int width, int height, int frint, int dispx, int dispy, … … 1224 1235 return retval; 1225 1236 } 1226 1237 1238 void 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 1227 1248 void OSD::ClearAllText(const QString &name) 1228 1249 { 1229 1250 osdlock.lock();