[haiku-commits] r38827 - in haiku/trunk/src/apps/mediaplayer: . interface playlist supplier support

  • From: superstippi@xxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Mon, 27 Sep 2010 17:26:41 +0200 (CEST)

Author: stippi
Date: 2010-09-27 17:26:41 +0200 (Mon, 27 Sep 2010)
New Revision: 38827
Changeset: http://dev.haiku-os.org/changeset/38827

Added:
   haiku/trunk/src/apps/mediaplayer/supplier/SubTitles.cpp
   haiku/trunk/src/apps/mediaplayer/supplier/SubTitles.h
   haiku/trunk/src/apps/mediaplayer/supplier/SubTitlesSRT.cpp
   haiku/trunk/src/apps/mediaplayer/supplier/SubTitlesSRT.h
   haiku/trunk/src/apps/mediaplayer/support/StackBlurFilter.cpp
   haiku/trunk/src/apps/mediaplayer/support/StackBlurFilter.h
Modified:
   haiku/trunk/src/apps/mediaplayer/Controller.cpp
   haiku/trunk/src/apps/mediaplayer/Controller.h
   haiku/trunk/src/apps/mediaplayer/ControllerObserver.cpp
   haiku/trunk/src/apps/mediaplayer/ControllerObserver.h
   haiku/trunk/src/apps/mediaplayer/Jamfile
   haiku/trunk/src/apps/mediaplayer/MainWin.cpp
   haiku/trunk/src/apps/mediaplayer/MainWin.h
   haiku/trunk/src/apps/mediaplayer/VideoView.cpp
   haiku/trunk/src/apps/mediaplayer/VideoView.h
   haiku/trunk/src/apps/mediaplayer/interface/SubtitleBitmap.cpp
   haiku/trunk/src/apps/mediaplayer/interface/SubtitleBitmap.h
   haiku/trunk/src/apps/mediaplayer/playlist/FilePlaylistItem.cpp
   haiku/trunk/src/apps/mediaplayer/supplier/MediaFileTrackSupplier.cpp
   haiku/trunk/src/apps/mediaplayer/supplier/MediaFileTrackSupplier.h
   haiku/trunk/src/apps/mediaplayer/supplier/TrackSupplier.h
   haiku/trunk/src/apps/mediaplayer/support/FileReadWrite.cpp
Log:
 * Added basic support for SRT subtitle files. It only works
   if the SRT file is placed alongside the current playlist
   item under the same name (sans extension). The name of the
   language is taken from the file which needs to be separated
   by a dot (should be improved).
 * Instead of the black outline, subtitles have a nice drop
   shadow now, which is easier on the eyes somehow.


Modified: haiku/trunk/src/apps/mediaplayer/Controller.cpp
===================================================================
--- haiku/trunk/src/apps/mediaplayer/Controller.cpp     2010-09-27 09:43:55 UTC 
(rev 38826)
+++ haiku/trunk/src/apps/mediaplayer/Controller.cpp     2010-09-27 15:26:41 UTC 
(rev 38827)
@@ -47,6 +47,7 @@
 #include "ProxyAudioSupplier.h"
 #include "ProxyVideoSupplier.h"
 #include "TrackSupplier.h"
+#include "SubTitles.h"
 #include "VideoTrackSupplier.h"
 
 using std::nothrow;
@@ -72,6 +73,7 @@
 void Controller::Listener::FileChanged(PlaylistItem* item, status_t result) {}
 void Controller::Listener::VideoTrackChanged(int32) {}
 void Controller::Listener::AudioTrackChanged(int32) {}
+void Controller::Listener::SubTitleTrackChanged(int32) {}
 void Controller::Listener::VideoStatsChanged() {}
 void Controller::Listener::AudioStatsChanged() {}
 void Controller::Listener::PlaybackStateChanged(uint32) {}
@@ -104,6 +106,8 @@
        fAudioSupplier(new ProxyAudioSupplier(this)),
        fVideoTrackSupplier(NULL),
        fAudioTrackSupplier(NULL),
+       fSubTitles(NULL),
+       fSubTitlesIndex(-1),
 
        fCurrentFrame(0),
        fDuration(0),
@@ -248,6 +252,8 @@
 
        fVideoTrackSupplier = NULL;
        fAudioTrackSupplier = NULL;
+       fSubTitles = NULL;
+       fSubTitlesIndex = -1;
 
        fCurrentFrame = 0;
        fDuration = 0;
@@ -433,6 +439,17 @@
 }
 
 
+int
+Controller::SubTitleTrackCount()
+{
+       BAutolock _(this);
+
+       if (fTrackSupplier != NULL)
+               return fTrackSupplier->CountSubTitleTracks();
+       return 0;
+}
+
+
 status_t
 Controller::SelectAudioTrack(int n)
 {
@@ -527,6 +544,58 @@
 }
 
 
+status_t
+Controller::SelectSubTitleTrack(int n)
+{
+       BAutolock _(this);
+
+       if (fTrackSupplier == NULL)
+               return B_NO_INIT;
+
+       fSubTitlesIndex = n;
+       fSubTitles = fTrackSupplier->SubTitleTrackForIndex(n);
+
+       const SubTitle* subTitle = NULL;
+       if (fSubTitles != NULL)
+               subTitle = fSubTitles->SubTitleAt(_TimePosition());
+       if (subTitle != NULL)
+               fVideoView->SetSubTitle(subTitle->text.String());
+       else
+               fVideoView->SetSubTitle(NULL);
+
+       _NotifySubTitleTrackChanged(n);
+       return B_OK;
+}
+
+
+int
+Controller::CurrentSubTitleTrack()
+{
+       BAutolock _(this);
+
+       if (fSubTitles == NULL)
+               return -1;
+
+       return fSubTitlesIndex;
+}
+
+
+const char*
+Controller::SubTitleTrackName(int n)
+{
+       BAutolock _(this);
+
+       if (fTrackSupplier == NULL)
+               return NULL;
+
+       const SubTitles* subTitles = fTrackSupplier->SubTitleTrackForIndex(n);
+       if (subTitles == NULL)
+               return NULL;
+
+       return subTitles->Name();
+}
+
+
 // #pragma mark -
 
 
@@ -1015,6 +1084,18 @@
 
 
 void
+Controller::_NotifySubTitleTrackChanged(int32 index) const
+{
+       BList listeners(fListeners);
+       int32 count = listeners.CountItems();
+       for (int32 i = 0; i < count; i++) {
+               Listener* listener = (Listener*)listeners.ItemAtFast(i);
+               listener->SubTitleTrackChanged(index);
+       }
+}
+
+
+void
 Controller::_NotifyVideoStatsChanged() const
 {
        BList listeners(fListeners);
@@ -1136,7 +1217,16 @@
 Controller::NotifyCurrentFrameChanged(int64 frame) const
 {
        fCurrentFrame = frame;
-       _NotifyPositionChanged((float)_TimePosition() / fDuration);
+       bigtime_t timePosition = _TimePosition();
+       _NotifyPositionChanged((float)timePosition / fDuration);
+
+       if (fSubTitles != NULL) {
+               const SubTitle* subTitle = fSubTitles->SubTitleAt(timePosition);
+               if (subTitle != NULL)
+                       fVideoView->SetSubTitle(subTitle->text.String());
+               else
+                       fVideoView->SetSubTitle(NULL);
+       }
 }
 
 

Modified: haiku/trunk/src/apps/mediaplayer/Controller.h
===================================================================
--- haiku/trunk/src/apps/mediaplayer/Controller.h       2010-09-27 09:43:55 UTC 
(rev 38826)
+++ haiku/trunk/src/apps/mediaplayer/Controller.h       2010-09-27 15:26:41 UTC 
(rev 38827)
@@ -40,6 +40,7 @@
 class PlaylistItem;
 class ProxyAudioSupplier;
 class ProxyVideoSupplier;
+class SubTitles;
 class VideoTrackSupplier;
 class VideoView;
 
@@ -57,6 +58,7 @@
 
                virtual void                    VideoTrackChanged(int32 index);
                virtual void                    AudioTrackChanged(int32 index);
+               virtual void                    SubTitleTrackChanged(int32 
index);
 
                virtual void                    VideoStatsChanged();
                virtual void                    AudioStatsChanged();
@@ -93,12 +95,16 @@
 
                        int                                     
AudioTrackCount();
                        int                                     
VideoTrackCount();
+                       int                                     
SubTitleTrackCount();
 
                        status_t                        SelectAudioTrack(int n);
                        int                                     
CurrentAudioTrack();
                        int                                     
AudioTrackChannelCount();
                        status_t                        SelectVideoTrack(int n);
                        int                                     
CurrentVideoTrack();
+                       status_t                        SelectSubTitleTrack(int 
n);
+                       int                                     
CurrentSubTitleTrack();
+                       const char*                     SubTitleTrackName(int 
n);
 
                        void                            Stop();
                        void                            Play();
@@ -158,6 +164,7 @@
                        void                            _NotifyFileFinished() 
const;
                        void                            
_NotifyVideoTrackChanged(int32 index) const;
                        void                            
_NotifyAudioTrackChanged(int32 index) const;
+                       void                            
_NotifySubTitleTrackChanged(int32 index) const;
 
                        void                            
_NotifyVideoStatsChanged() const;
                        void                            
_NotifyAudioStatsChanged() const;
@@ -196,6 +203,8 @@
                        ProxyAudioSupplier*     fAudioSupplier;
                        VideoTrackSupplier*     fVideoTrackSupplier;
                        AudioTrackSupplier*     fAudioTrackSupplier;
+                       const SubTitles*        fSubTitles;
+                       int32                           fSubTitlesIndex;
 
        mutable int64                           fCurrentFrame;
                        bigtime_t                       fDuration;

Modified: haiku/trunk/src/apps/mediaplayer/ControllerObserver.cpp
===================================================================
--- haiku/trunk/src/apps/mediaplayer/ControllerObserver.cpp     2010-09-27 
09:43:55 UTC (rev 38826)
+++ haiku/trunk/src/apps/mediaplayer/ControllerObserver.cpp     2010-09-27 
15:26:41 UTC (rev 38827)
@@ -84,6 +84,19 @@
 
 
 void
+ControllerObserver::SubTitleTrackChanged(int32 index)
+{
+       if (!(fObserveFlags & OBSERVE_TRACK_CHANGES))
+               return;
+
+       BMessage message(MSG_CONTROLLER_SUB_TITLE_TRACK_CHANGED);
+       message.AddInt32("index", index);
+
+       DeliverMessage(message);
+}
+
+
+void
 ControllerObserver::VideoStatsChanged()
 {
        if (!(fObserveFlags & OBSERVE_STAT_CHANGES))

Modified: haiku/trunk/src/apps/mediaplayer/ControllerObserver.h
===================================================================
--- haiku/trunk/src/apps/mediaplayer/ControllerObserver.h       2010-09-27 
09:43:55 UTC (rev 38826)
+++ haiku/trunk/src/apps/mediaplayer/ControllerObserver.h       2010-09-27 
15:26:41 UTC (rev 38827)
@@ -19,6 +19,7 @@
 
        MSG_CONTROLLER_VIDEO_TRACK_CHANGED              = 'cnvt',
        MSG_CONTROLLER_AUDIO_TRACK_CHANGED              = 'cnat',
+       MSG_CONTROLLER_SUB_TITLE_TRACK_CHANGED  = 'cnst',
 
        MSG_CONTROLLER_VIDEO_STATS_CHANGED              = 'cnvs',
        MSG_CONTROLLER_AUDIO_STATS_CHANGED              = 'cnas',
@@ -55,6 +56,7 @@
 
        virtual void            VideoTrackChanged(int32 index);
        virtual void            AudioTrackChanged(int32 index);
+       virtual void            SubTitleTrackChanged(int32 index);
 
        virtual void            VideoStatsChanged();
        virtual void            AudioStatsChanged();

Modified: haiku/trunk/src/apps/mediaplayer/Jamfile
===================================================================
--- haiku/trunk/src/apps/mediaplayer/Jamfile    2010-09-27 09:43:55 UTC (rev 
38826)
+++ haiku/trunk/src/apps/mediaplayer/Jamfile    2010-09-27 15:26:41 UTC (rev 
38827)
@@ -3,6 +3,7 @@
 # for BRecentItems
 UsePublicHeaders [ FDirName be_apps Tracker ] ;
 UsePrivateHeaders interface shared ;
+UseLibraryHeaders agg ;
 
 # source directories
 local sourceDirs =
@@ -82,6 +83,8 @@
        ProxyAudioSupplier.cpp
        ProxyVideoSupplier.cpp
        TrackSupplier.cpp
+       SubTitles.cpp
+       SubTitlesSRT.cpp
        VideoTrackSupplier.cpp
 
        # support
@@ -99,6 +102,7 @@
        Notifier.cpp
        RWLocker.cpp
        SettingsMessage.cpp
+       StackBlurFilter.cpp
 
        # .
        Controller.cpp

Modified: haiku/trunk/src/apps/mediaplayer/MainWin.cpp
===================================================================
--- haiku/trunk/src/apps/mediaplayer/MainWin.cpp        2010-09-27 09:43:55 UTC 
(rev 38826)
+++ haiku/trunk/src/apps/mediaplayer/MainWin.cpp        2010-09-27 15:26:41 UTC 
(rev 38827)
@@ -95,10 +95,12 @@
        M_ASPECT_37_20,
        M_ASPECT_47_20,
 
-       M_SELECT_AUDIO_TRACK            = 0x00000800,
-       M_SELECT_AUDIO_TRACK_END        = 0x00000fff,
-       M_SELECT_VIDEO_TRACK            = 0x00010000,
-       M_SELECT_VIDEO_TRACK_END        = 0x000fffff,
+       M_SELECT_AUDIO_TRACK                    = 0x00000800,
+       M_SELECT_AUDIO_TRACK_END                = 0x00000fff,
+       M_SELECT_VIDEO_TRACK                    = 0x00010000,
+       M_SELECT_VIDEO_TRACK_END                = 0x00010fff,
+       M_SELECT_SUB_TITLE_TRACK                = 0x00020000,
+       M_SELECT_SUB_TITLE_TRACK_END    = 0x00020fff,
 
        M_SET_RATING,
 
@@ -680,6 +682,22 @@
                        }
                        break;
                }
+               case MSG_CONTROLLER_SUB_TITLE_TRACK_CHANGED:
+               {
+                       int32 index;
+                       if (msg->FindInt32("index", &index) == B_OK) {
+                               int32 i = 0;
+                               while (BMenuItem* item = 
fSubTitleTrackMenu->ItemAt(i)) {
+                                       BMessage* message = item->Message();
+                                       if (message != NULL) {
+                                               
item->SetMarked((int32)message->what
+                                                       - 
M_SELECT_SUB_TITLE_TRACK == index);
+                                       }
+                                       i++;
+                               }
+                       }
+                       break;
+               }
                case MSG_CONTROLLER_PLAYBACK_STATE_CHANGED:
                {
                        uint32 state;
@@ -971,6 +989,12 @@
                                fController->SelectVideoTrack(msg->what - 
M_SELECT_VIDEO_TRACK);
                                break;
                        }
+                       if ((int32)msg->what >= M_SELECT_SUB_TITLE_TRACK - 1
+                               && msg->what <= M_SELECT_SUB_TITLE_TRACK_END) {
+                               
fController->SelectSubTitleTrack((int32)msg->what
+                                       - M_SELECT_SUB_TITLE_TRACK);
+                               break;
+                       }
                        // let BWindow handle the rest
                        BWindow::MessageReceived(msg);
        }
@@ -1329,7 +1353,7 @@
 {
 //     printf("MainWin::_SetupWindow\n");
        // Populate the track menus
-       _SetupTrackMenus(fAudioTrackMenu, fVideoTrackMenu);
+       _SetupTrackMenus(fAudioTrackMenu, fVideoTrackMenu, fSubTitleTrackMenu);
        _UpdateAudioChannelCount(fController->CurrentAudioTrack());
 
        fVideoMenu->SetEnabled(fHasVideo);
@@ -1382,6 +1406,7 @@
        fVideoAspectMenu = new BMenu("Aspect ratio");
        fAudioTrackMenu = new BMenu("Track");
        fVideoTrackMenu = new BMenu("Track");
+       fSubTitleTrackMenu = new BMenu("Subtitles");
        fAttributesMenu = new BMenu("Attributes");
 
        fMenuBar->AddItem(fFileMenu);
@@ -1446,6 +1471,7 @@
        fAudioMenu->AddItem(fAudioTrackMenu);
 
        fVideoMenu->AddItem(fVideoTrackMenu);
+       fVideoMenu->AddItem(fSubTitleTrackMenu);
        fVideoMenu->AddSeparatorItem();
        BMessage* resizeMessage = new BMessage(M_VIEW_SIZE);
        resizeMessage->AddInt32("size", 50);
@@ -1544,10 +1570,12 @@
 
 
 void
-MainWin::_SetupTrackMenus(BMenu* audioTrackMenu, BMenu* videoTrackMenu)
+MainWin::_SetupTrackMenus(BMenu* audioTrackMenu, BMenu* videoTrackMenu,
+       BMenu* subTitleTrackMenu)
 {
        audioTrackMenu->RemoveItems(0, audioTrackMenu->CountItems(), true);
        videoTrackMenu->RemoveItems(0, videoTrackMenu->CountItems(), true);
+       subTitleTrackMenu->RemoveItems(0, subTitleTrackMenu->CountItems(), 
true);
 
        char s[100];
 
@@ -1590,6 +1618,33 @@
                videoTrackMenu->AddItem(new BMenuItem("none", new 
BMessage(M_DUMMY)));
                videoTrackMenu->ItemAt(0)->SetMarked(true);
        }
+
+       count = fController->SubTitleTrackCount();
+       if (count > 0) {
+               current = fController->CurrentSubTitleTrack();
+               BMenuItem* item = new BMenuItem("Off",
+                       new BMessage(M_SELECT_SUB_TITLE_TRACK - 1));
+               subTitleTrackMenu->AddItem(item);
+               item->SetMarked(current == -1);
+
+               subTitleTrackMenu->AddSeparatorItem();
+
+               for (int i = 0; i < count; i++) {
+                       const char* name = fController->SubTitleTrackName(i);
+                       if (name != NULL)
+                               snprintf(s, sizeof(s), "%s", name);
+                       else
+                               snprintf(s, sizeof(s), "Track %d", i + 1);
+                       item = new BMenuItem(s,
+                               new BMessage(M_SELECT_SUB_TITLE_TRACK + i));
+                       item->SetMarked(i == current);
+                       subTitleTrackMenu->AddItem(item);
+               }
+       } else {
+               subTitleTrackMenu->AddItem(new BMenuItem("none",
+                       new BMessage(M_DUMMY)));
+               subTitleTrackMenu->ItemAt(0)->SetMarked(true);
+       }
 }
 
 
@@ -1945,10 +2000,12 @@
        // Add track selector menus
        BMenu* audioTrackMenu = new BMenu("Audio track");
        BMenu* videoTrackMenu = new BMenu("Video track");
-       _SetupTrackMenus(audioTrackMenu, videoTrackMenu);
+       BMenu* subTitleTrackMenu = new BMenu("Subtitles");
+       _SetupTrackMenus(audioTrackMenu, videoTrackMenu, subTitleTrackMenu);
 
        audioTrackMenu->SetTargetForItems(this);
        videoTrackMenu->SetTargetForItems(this);
+       subTitleTrackMenu->SetTargetForItems(this);
 
        menu->AddItem(item = new BMenuItem(audioTrackMenu));
        item->SetEnabled(fHasAudio);
@@ -1956,6 +2013,9 @@
        menu->AddItem(item = new BMenuItem(videoTrackMenu));
        item->SetEnabled(fHasVideo);
 
+       menu->AddItem(item = new BMenuItem(subTitleTrackMenu));
+       item->SetEnabled(fHasVideo);
+
        menu->AddSeparatorItem();
        menu->AddItem(new BMenuItem("Quit", new BMessage(M_FILE_QUIT), 'Q'));
 

Modified: haiku/trunk/src/apps/mediaplayer/MainWin.h
===================================================================
--- haiku/trunk/src/apps/mediaplayer/MainWin.h  2010-09-27 09:43:55 UTC (rev 
38826)
+++ haiku/trunk/src/apps/mediaplayer/MainWin.h  2010-09-27 15:26:41 UTC (rev 
38827)
@@ -89,7 +89,8 @@
                        void                            _CreateMenu();
                        void                            
_SetupVideoAspectItems(BMenu* menu);
                        void                            _SetupTrackMenus(BMenu* 
audioTrackMenu,
-                                                                       BMenu* 
videoTrackMenu);
+                                                                       BMenu* 
videoTrackMenu,
+                                                                       BMenu* 
subTitleTrackMenu);
                        void                            
_UpdateAudioChannelCount(int32 audioTrackIndex);
 
                        void                            
_GetMinimumWindowSize(int& width,
@@ -152,6 +153,7 @@
                        BMenu*                          fVideoAspectMenu;
                        BMenu*                          fAudioTrackMenu;
                        BMenu*                          fVideoTrackMenu;
+                       BMenu*                          fSubTitleTrackMenu;
                        BMenuItem*                      fNoInterfaceMenuItem;
                        BMenu*                          fAttributesMenu;
                        BMenu*                          fRatingMenu;

Modified: haiku/trunk/src/apps/mediaplayer/VideoView.cpp
===================================================================
--- haiku/trunk/src/apps/mediaplayer/VideoView.cpp      2010-09-27 09:43:55 UTC 
(rev 38826)
+++ haiku/trunk/src/apps/mediaplayer/VideoView.cpp      2010-09-27 15:26:41 UTC 
(rev 38827)
@@ -290,15 +290,20 @@
 
 
 void
-VideoView::SetSubtitle(const char* text)
+VideoView::SetSubTitle(const char* text)
 {
        if (text == NULL || text[0] == '\0') {
                fHasSubtitle = false;
-               return;
+       } else {
+               fHasSubtitle = true;
+               fSubtitleBitmap->SetText(text);
        }
-
-       fHasSubtitle = true;
-       fSubtitleBitmap->SetText(text);
+       // TODO: Make smarter and invalidate only previous subtitle bitmap
+       // region;
+       if (!fIsPlaying && LockLooper()) {
+               Invalidate();
+               UnlockLooper();
+       }
 }
 
 

Modified: haiku/trunk/src/apps/mediaplayer/VideoView.h
===================================================================
--- haiku/trunk/src/apps/mediaplayer/VideoView.h        2010-09-27 09:43:55 UTC 
(rev 38826)
+++ haiku/trunk/src/apps/mediaplayer/VideoView.h        2010-09-27 15:26:41 UTC 
(rev 38827)
@@ -51,7 +51,7 @@
                        void                            SetFullscreen(bool 
fullScreen);
                        void                            SetVideoFrame(const 
BRect& frame);
 
-                       void                            SetSubtitle(const char* 
text);
+                       void                            SetSubTitle(const char* 
text);
 
 private:
                        void                            _DrawBitmap(const 
BBitmap* bitmap);

Modified: haiku/trunk/src/apps/mediaplayer/interface/SubtitleBitmap.cpp
===================================================================
--- haiku/trunk/src/apps/mediaplayer/interface/SubtitleBitmap.cpp       
2010-09-27 09:43:55 UTC (rev 38826)
+++ haiku/trunk/src/apps/mediaplayer/interface/SubtitleBitmap.cpp       
2010-09-27 15:26:41 UTC (rev 38827)
@@ -11,7 +11,9 @@
 #include <Bitmap.h>
 #include <TextView.h>
 
+#include "StackBlurFilter.h"
 
+
 SubtitleBitmap::SubtitleBitmap()
        :
        fBitmap(NULL),
@@ -77,11 +79,15 @@
 
        delete fBitmap;
 
-       BRect bounds = _InsertText();
+       BRect bounds;
+       float outlineRadius;
+       _InsertText(bounds, outlineRadius);
 
        fBitmap = new BBitmap(bounds, B_BITMAP_ACCEPTS_VIEWS, B_RGBA32);
        memset(fBitmap->Bits(), 0, fBitmap->BitsLength());
 
+       StackBlurFilter filter;
+
        if (fBitmap->Lock()) {
                fBitmap->AddChild(fShadowTextView);
                fShadowTextView->ResizeTo(bounds.Width(), bounds.Height());
@@ -97,8 +103,11 @@
                fShadowTextView->Sync();
                fShadowTextView->RemoveSelf();
 
+               filter.Filter(fBitmap, outlineRadius * 2);
+
                fBitmap->AddChild(fTextView);
                fTextView->ResizeTo(bounds.Width(), bounds.Height());
+               fTextView->MoveTo(-outlineRadius / 2, -outlineRadius / 2);
 
                fTextView->SetViewColor(0, 0, 0, 0);
                fTextView->SetDrawingMode(B_OP_ALPHA);
@@ -273,12 +282,12 @@
 }
 
 
-BRect
-SubtitleBitmap::_InsertText()
+void
+SubtitleBitmap::_InsertText(BRect& textRect, float& outlineRadius)
 {
        BFont font(be_plain_font);
-       float fontSize = ceilf((fVideoBounds.Width() * 0.9) / 35);
-       float falseBoldWidth = ceilf(fontSize / 28.0);
+       float fontSize = ceilf((fVideoBounds.Width() * 0.9) / 36);
+       outlineRadius = ceilf(fontSize / 28.0);
        font.SetSize(fontSize);
 
        rgb_color shadow;
@@ -293,8 +302,8 @@
        color.blue = 255;
        color.alpha = 240;
 
-       BRect textRect = fVideoBounds;
-       textRect.OffsetBy(falseBoldWidth, falseBoldWidth);
+       textRect = fVideoBounds;
+       textRect.OffsetBy(outlineRadius, outlineRadius);
 
        fTextView->SetText(NULL);
        fTextView->SetFontAndColor(&font, B_FONT_ALL, &color);
@@ -302,7 +311,7 @@
        fTextView->Insert(" ");
        parse_text(fText, fTextView, font, color, true);
 
-       font.SetFalseBoldWidth(falseBoldWidth);
+       font.SetFalseBoldWidth(outlineRadius);
        fShadowTextView->SetText(NULL);
        fShadowTextView->SetFontAndColor(&font, B_FONT_ALL, &shadow);
 
@@ -316,9 +325,16 @@
        fShadowTextView->SetTextRect(textRect);
 
        textRect = fTextView->TextRect();
-       textRect.InsetBy(-falseBoldWidth, -falseBoldWidth);
+       textRect.InsetBy(-outlineRadius, -outlineRadius);
        textRect.OffsetTo(B_ORIGIN);
-       return textRect;
+
+       // Make sure the text rect really finishes behind the last line.
+       // We don't want any accidental extra space.
+       textRect.bottom = outlineRadius;
+       int32 lineCount = fTextView->CountLines();
+       for (int32 i = 0; i < lineCount; i++)
+               textRect.bottom += fTextView->LineHeight(i);
+       textRect.bottom += outlineRadius;
 }
 
 

Modified: haiku/trunk/src/apps/mediaplayer/interface/SubtitleBitmap.h
===================================================================
--- haiku/trunk/src/apps/mediaplayer/interface/SubtitleBitmap.h 2010-09-27 
09:43:55 UTC (rev 38826)
+++ haiku/trunk/src/apps/mediaplayer/interface/SubtitleBitmap.h 2010-09-27 
15:26:41 UTC (rev 38827)
@@ -26,7 +26,8 @@
 
 private:
                        void                            _GenerateBitmap();
-                       BRect                           _InsertText();
+                       void                            _InsertText(BRect& 
bounds,
+                                                                       float& 
outlineRadius);
 
 private:
                        BBitmap*                        fBitmap;

Modified: haiku/trunk/src/apps/mediaplayer/playlist/FilePlaylistItem.cpp
===================================================================
--- haiku/trunk/src/apps/mediaplayer/playlist/FilePlaylistItem.cpp      
2010-09-27 09:43:55 UTC (rev 38826)
+++ haiku/trunk/src/apps/mediaplayer/playlist/FilePlaylistItem.cpp      
2010-09-27 15:26:41 UTC (rev 38827)
@@ -16,6 +16,7 @@
 #include <Path.h>
 
 #include "MediaFileTrackSupplier.h"
+#include "SubTitlesSRT.h"
 
 
 static const char* kPathKey = "path";
@@ -346,11 +347,65 @@
        BMediaFile* mediaFile = new(std::nothrow) BMediaFile(&fRef);
        if (mediaFile == NULL)
                return NULL;
-       TrackSupplier* supplier
+       MediaFileTrackSupplier* supplier
                = new(std::nothrow) MediaFileTrackSupplier(mediaFile);
-       if (supplier == NULL)
+       if (supplier == NULL) {
                delete mediaFile;
+               return NULL;
+       }
 
+       // Search for subtitle files in the same folder
+       // TODO: Error checking
+       BEntry entry(&fRef, true);
+
+       char originalName[B_FILE_NAME_LENGTH];
+       entry.GetName(originalName);
+       BString nameWithoutExtension(originalName);
+       int32 extension = nameWithoutExtension.FindLast('.');
+       if (extension > 0)
+               nameWithoutExtension.Truncate(extension);
+
+       BPath path;
+       entry.GetPath(&path);
+       path.GetParent(&path);
+       BDirectory directory(path.Path());
+       while (directory.GetNextEntry(&entry) == B_OK) {
+               char name[B_FILE_NAME_LENGTH];
+               if (entry.GetName(name) != B_OK)
+                       continue;
+               BString nameString(name);
+               if (nameString == originalName)
+                       continue;
+               if (nameString.IFindFirst(nameWithoutExtension) < 0)
+                       continue;
+
+               BFile file(&entry, B_READ_ONLY);
+               if (file.InitCheck() != B_OK)
+                       continue;
+
+               int32 pos = nameString.FindLast('.');
+               if (pos < 0)
+                       continue;
+
+               BString extensionString(nameString.String() + pos + 1);
+               extensionString.ToLower();
+
+               BString language = "default";
+               if (pos > 1) {
+                       int32 end = pos;
+                       while (pos > 0 && *(nameString.String() + pos - 1) != 
'.')
+                               pos--;
+                       language.SetTo(nameString.String() + pos, end - pos);
+               }
+
+               if (extensionString == "srt") {
+                       SubTitles* subTitles
+                               = new(std::nothrow) SubTitlesSRT(&file, 
language.String());
+                       if (subTitles != NULL && 
!supplier->AddSubTitles(subTitles))
+                               delete subTitles;
+               }
+       }
+
        return supplier;
 }
 

Modified: haiku/trunk/src/apps/mediaplayer/supplier/MediaFileTrackSupplier.cpp
===================================================================
--- haiku/trunk/src/apps/mediaplayer/supplier/MediaFileTrackSupplier.cpp        
2010-09-27 09:43:55 UTC (rev 38826)
+++ haiku/trunk/src/apps/mediaplayer/supplier/MediaFileTrackSupplier.cpp        
2010-09-27 15:26:41 UTC (rev 38827)
@@ -69,7 +69,9 @@
 {
        delete fMediaFile;
                // BMediaFile destructor will call ReleaseAllTracks()
-}
+       for (int32 i = fSubTitleTracks.CountItems() - 1; i >= 0; i--)
+               delete 
reinterpret_cast<SubTitles*>(fSubTitleTracks.ItemAtFast(i));
+ }
 
 
 status_t
@@ -115,6 +117,13 @@
 }
 
 
+int32
+MediaFileTrackSupplier::CountSubTitleTracks()
+{
+       return fSubTitleTracks.CountItems();
+}
+
+
 status_t
 MediaFileTrackSupplier::GetAudioMetaData(int32 index, BMessage* metaData)
 {
@@ -166,3 +175,17 @@
        return supplier;
 }
 
+
+const SubTitles*
+MediaFileTrackSupplier::SubTitleTrackForIndex(int32 index)
+{
+       return reinterpret_cast<SubTitles*>(fSubTitleTracks.ItemAt(index));
+}
+
+
+bool
+MediaFileTrackSupplier::AddSubTitles(SubTitles* subTitles)
+{
+       return fSubTitleTracks.AddItem(subTitles);
+}
+

Modified: haiku/trunk/src/apps/mediaplayer/supplier/MediaFileTrackSupplier.h
===================================================================
--- haiku/trunk/src/apps/mediaplayer/supplier/MediaFileTrackSupplier.h  
2010-09-27 09:43:55 UTC (rev 38826)
+++ haiku/trunk/src/apps/mediaplayer/supplier/MediaFileTrackSupplier.h  
2010-09-27 15:26:41 UTC (rev 38827)
@@ -28,6 +28,7 @@
 
        virtual int32                           CountAudioTracks();
        virtual int32                           CountVideoTracks();
+       virtual int32                           CountSubTitleTracks();
 
        virtual status_t                        GetAudioMetaData(int32 index,
                                                                        
BMessage* metaData);
@@ -36,11 +37,15 @@
 
        virtual AudioTrackSupplier*     CreateAudioTrackForIndex(int32 index);
        virtual VideoTrackSupplier*     CreateVideoTrackForIndex(int32 index);
+       virtual const SubTitles*        SubTitleTrackForIndex(int32 index);
 
+                       bool                            AddSubTitles(SubTitles* 
subTitles);
+
 private:
                        BMediaFile*                     fMediaFile;
                        BList                           fAudioTracks;
                        BList                           fVideoTracks;
+                       BList                           fSubTitleTracks;
 };
 
 

Added: haiku/trunk/src/apps/mediaplayer/supplier/SubTitles.cpp
===================================================================
--- haiku/trunk/src/apps/mediaplayer/supplier/SubTitles.cpp                     
        (rev 0)
+++ haiku/trunk/src/apps/mediaplayer/supplier/SubTitles.cpp     2010-09-27 
15:26:41 UTC (rev 38827)
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2010, Stephan Aßmus <superstippi@xxxxxx>. All rights reserved.
+ * Distributed under the terms of the MIT License.
+ */
+
+
+#include "SubTitles.h"
+
+
+SubTitles::SubTitles()
+{
+}
+
+
+SubTitles::~SubTitles()
+{
+}

Added: haiku/trunk/src/apps/mediaplayer/supplier/SubTitles.h
===================================================================
--- haiku/trunk/src/apps/mediaplayer/supplier/SubTitles.h                       
        (rev 0)
+++ haiku/trunk/src/apps/mediaplayer/supplier/SubTitles.h       2010-09-27 
15:26:41 UTC (rev 38827)
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2010, Stephan Aßmus <superstippi@xxxxxx>. All rights reserved.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef SUB_TITLES_H
+#define SUB_TITLES_H
+
+
+#include <Point.h>
+#include <String.h>
+
+
+class BFile;
+
+
+struct SubTitle {
+       BString         text;
+       BPoint          placement;
+       bigtime_t       startTime;
+       bigtime_t       duration;
+};
+
+
+class SubTitles {
+public:
+                                                               SubTitles();
+       virtual                                         ~SubTitles();
+
+       virtual const char*                     Name() const = 0;
+       virtual const SubTitle*         SubTitleAt(bigtime_t time) const = 0;
+};
+
+
+#endif //SUB_TITLES_H

Added: haiku/trunk/src/apps/mediaplayer/supplier/SubTitlesSRT.cpp
===================================================================
--- haiku/trunk/src/apps/mediaplayer/supplier/SubTitlesSRT.cpp                  
        (rev 0)
+++ haiku/trunk/src/apps/mediaplayer/supplier/SubTitlesSRT.cpp  2010-09-27 
15:26:41 UTC (rev 38827)
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2010, Stephan Aßmus <superstippi@xxxxxx>. All rights reserved.
+ * Distributed under the terms of the MIT License.
+ */
+
+
+#include "SubTitlesSRT.h"
+
+#include <new>
+
+#include <stdlib.h>
+
+#include <File.h>
+
+#include "FileReadWrite.h"
+
+
+SubTitlesSRT::SubTitlesSRT(BFile* file, const char* name)
+       :
+       SubTitles(),
+       fName(name),
+       fSubTitles(64)
+{
+       if (file == NULL)
+               return;
+       if (file->InitCheck() != B_OK)
+               return;
+
+       FileReadWrite lineProvider(file);
+       BString line;
+       enum {
+               EXPECT_SEQUENCE_NUMBER = 0,
+               EXPECT_TIME_CODE,
+               EXPECT_TEXT
+       };
+
+       SubTitle subTitle;
+       int32 lastSequenceNumber = 0;
+       int32 currentLine = 0;
+
+       int32 state = EXPECT_SEQUENCE_NUMBER;
+       while (lineProvider.Next(line)) {
+               line.RemoveAll("\n");
+               line.RemoveAll("\r");
+               switch (state) {
+                       case EXPECT_SEQUENCE_NUMBER:
+                       {
+                               line.Trim();
+                               int32 sequenceNumber = atoi(line.String());
+                               if (sequenceNumber != lastSequenceNumber + 1) {
+                                       fprintf(stderr, "Warning: Wrong 
sequence number in SRT "
+                                               "file: %ld, expected: %ld, line 
%ld\n", sequenceNumber,
+                                               lastSequenceNumber + 1, 
currentLine);
+                               }
+                               state = EXPECT_TIME_CODE;
+                               lastSequenceNumber = sequenceNumber;
+                               break;
+                       }
+
+                       case EXPECT_TIME_CODE:
+                       {
+                               line.Trim();
+                               int32 separatorPos = line.FindFirst(" --> ");
+                               if (separatorPos < 0) {
+                                       fprintf(stderr, "Error: Time code 
expected on line %ld, "
+                                               "got '%s'\n", currentLine, 
line.String());
+                                       return;
+                               }
+                               BString timeCode(line.String(), separatorPos);
+                               if (separatorPos != 12) {
+                                       fprintf(stderr, "Warning: Time code 
broken on line %ld "
+                                               "(%s)?\n", currentLine, 
timeCode.String());
+                               }
+                               int hours;
+                               int minutes;
+                               int seconds;
+                               int milliSeconds;
+                               if (sscanf(timeCode.String(), "%d:%d:%d,%d", 
&hours, &minutes,
+                                       &seconds, &milliSeconds) != 4) {
+                                       fprintf(stderr, "Error: Failed to parse 
start time on "
+                                               "line %ld\n", currentLine);
+                                       return;
+                               }
+                               subTitle.startTime = (bigtime_t)hours * 60 * 60 
* 1000000LL
+                                       + (bigtime_t)minutes * 60 * 1000000LL
+                                       + (bigtime_t)seconds * 1000000LL
+                                       + (bigtime_t)milliSeconds * 1000;
+
+                               int32 endTimePos = separatorPos + 5;
+                               timeCode.SetTo(line.String() + endTimePos);
+                               if (sscanf(timeCode.String(), "%d:%d:%d,%d", 
&hours, &minutes,
+                                       &seconds, &milliSeconds) != 4) {
+                                       fprintf(stderr, "Error: Failed to parse 
end time on "
+                                               "line %ld\n", currentLine);
+                                       return;
+                               }
+                               bigtime_t endTime = (bigtime_t)hours * 60 * 60 
* 1000000LL
+                                       + (bigtime_t)minutes * 60 * 1000000LL
+                                       + (bigtime_t)seconds * 1000000LL
+                                       + (bigtime_t)milliSeconds * 1000;
+
+                               subTitle.duration = endTime - 
subTitle.startTime;
+
+                               state = EXPECT_TEXT;
+                               break;
+                       }
+
+                       case EXPECT_TEXT:
+                               if (line.Length() == 0) {
+                                       int32 index = 
_IndexFor(subTitle.startTime);
+                                       SubTitle* clone = new(std::nothrow) 
SubTitle(subTitle);
+                                       if (clone == NULL || 
!fSubTitles.AddItem(clone, index)) {
+                                               delete clone;
+                                               return;
+                                       }
+                                       subTitle.text = "";
+                                       subTitle.placement = BPoint(-1, -1);
+                                       subTitle.startTime = 0;
+                                       subTitle.duration = 0;
+
+                                       state = EXPECT_SEQUENCE_NUMBER;
+                               } else
+                                       subTitle.text << line << '\n';
+                               break;
+               }
+               line.SetTo("");
+               currentLine++;
+       }
+}
+
+
+SubTitlesSRT::~SubTitlesSRT()
+{
+       for (int32 i = fSubTitles.CountItems() - 1; i >= 0; i--)
+               delete reinterpret_cast<SubTitle*>(fSubTitles.ItemAtFast(i));
+}
+
+
+const char*
+SubTitlesSRT::Name() const
+{
+       return fName.String();
+}
+
+
+const SubTitle*
+SubTitlesSRT::SubTitleAt(bigtime_t time) const
+{
+       int32 index = _IndexFor(time);
+       SubTitle* subTitle
+               = reinterpret_cast<SubTitle*>(fSubTitles.ItemAt(index));
+       if (subTitle != NULL && subTitle->startTime > time)

[... truncated: 793 lines follow ...]

Other related posts: