Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Karaoke video background player with a generic decoder class #1137

Closed
wants to merge 2 commits into from

6 participants

@gyunaev
Collaborator

As requested by Spiff :)

Same functionality as in #1126, but for Windows the files should be already there in the build system. Not for Mac though - you'll need to add new files xbmc/music/karaoke/karaokevideobackground.cpp / h and xbmc/video/FFmpegVideoDecoder.cpp /h

@gyunaev
Collaborator

Any feedback?

@gyunaev
Collaborator

What does "alpha" mean? :)

Is the ffmpeg library VFS-patched, i.e. its open() goes through the VFS already? At least DVDPlayer calls avformat_open_input() directly, see xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp

@jmarshallnz
Owner

alphabetical.

@gyunaev
Collaborator

Everything should be fixed by now.

@ghost

the ffmpeg demuxer checks the input stream type given. it's only DVDSTREAM_TYPE_FFMPEG for a few streaming protocols, mms, rtsp. usually it's DVDSTREAM_TYPE_FILE which reads through our vfs.

@ghost

rebase and inject. elupus indirectly signed off on devcon.

@gyunaev
Collaborator
@ghost

merge window is closed. will have to wait till october.

@leechguy

This PR seems to be obsoleted by 01a2ea0

@bulkzooi

So this can be closed?

@MartijnKaijser

@bulkzooi are you a dev? No? then stay out of xbmc github

@MartijnKaijser

@gyunaev
is this PR indeed obsolete as mentioned?

@tru tru referenced this pull request from a commit in RasPlex/plex-home-theatre
@tru tru Fix "Play Next" action.
Fixes #1137
cdb497f
@tru tru referenced this pull request from a commit in RasPlex/plex-home-theatre
@tru tru Fix "Play Next" action.
Fixes #1137
8981d82
@MartijnKaijser MartijnKaijser removed this from the Awaiting answer from dev milestone
@mkortstiege mkortstiege closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jul 9, 2012
Commits on Jul 11, 2012
  1. Fixed alpha and identations

    Oldnemesis authored
This page is out of date. Refresh to see the latest.
View
6 project/VS2010Express/XBMC.vcxproj
@@ -743,6 +743,7 @@
<ClCompile Include="..\..\xbmc\music\karaoke\karaokelyricstextlrc.cpp" />
<ClCompile Include="..\..\xbmc\music\karaoke\karaokelyricstextustar.cpp" />
<ClCompile Include="..\..\xbmc\music\karaoke\karaokewindowbackground.cpp" />
+ <ClCompile Include="..\..\xbmc\music\karaoke\karaokevideobackground.cpp" />
<ClCompile Include="..\..\xbmc\music\LastFmManager.cpp" />
<ClCompile Include="..\..\xbmc\music\MusicDatabase.cpp" />
<ClCompile Include="..\..\xbmc\music\MusicInfoLoader.cpp" />
@@ -928,6 +929,8 @@
<ClInclude Include="..\..\xbmc\filesystem\windows\WINSMBDirectory.h" />
<ClInclude Include="..\..\xbmc\input\windows\WINJoystick.h" />
<ClInclude Include="..\..\xbmc\interfaces\python\xbmcmodule\pythreadstate.h" />
+ <ClInclude Include="..\..\xbmc\music\karaoke\karaokevideobackground.h" />
+ <ClInclude Include="..\..\xbmc\video\FFmpegVideoDecoder.h" />
<ClInclude Include="..\..\xbmc\network\httprequesthandler\HTTPImageHandler.h" />
<ClInclude Include="..\..\xbmc\network\AirTunesServer.h" />
<ClInclude Include="..\..\xbmc\network\DllLibShairplay.h" />
@@ -1135,6 +1138,7 @@
<ClCompile Include="..\..\xbmc\video\dialogs\GUIDialogVideoOverlay.cpp" />
<ClCompile Include="..\..\xbmc\video\dialogs\GUIDialogVideoScan.cpp" />
<ClCompile Include="..\..\xbmc\video\dialogs\GUIDialogVideoSettings.cpp" />
+ <ClCompile Include="..\..\xbmc\video\FFmpegVideoDecoder.cpp" />
<ClCompile Include="..\..\xbmc\video\GUIViewStateVideo.cpp" />
<ClCompile Include="..\..\xbmc\video\Teletext.cpp" />
<ClCompile Include="..\..\xbmc\video\VideoDatabase.cpp" />
@@ -2283,4 +2287,4 @@
</VisualStudio>
</ProjectExtensions>
<Import Project="$(SolutionDir)\$(ProjectFileName).targets.user" Condition="Exists('$(SolutionDir)\$(ProjectFileName).targets.user')" />
-</Project>
+</Project>
View
5 project/VS2010Express/XBMC.vcxproj.filters
@@ -2586,6 +2586,9 @@
<ClCompile Include="..\..\xbmc\utils\DatabaseUtils.cpp">
<Filter>utils</Filter>
</ClCompile>
+ <ClCompile Include="..\..\xbmc\music\karaoke\karaokevideobackground.cpp">
+ <Filter>music\karaoke</Filter>
+ </ClCompile>
<ClCompile Include="..\..\xbmc\filesystem\VideoDatabaseDirectory\DirectoryNodeTags.cpp">
<Filter>filesystem\VideoDatabaseDirectory</Filter>
</ClCompile>
@@ -5233,4 +5236,4 @@
<Filter>win32</Filter>
</CustomBuild>
</ItemGroup>
-</Project>
+</Project>
View
2  xbmc/music/karaoke/GUIWindowKaraokeLyrics.cpp
@@ -142,7 +142,7 @@ void CGUIWindowKaraokeLyrics::newSong(CKaraokeLyrics * lyrics)
// Start the required video
m_Lyrics->GetVideoParameters( path, offset );
- m_Background->StartVideo( path, offset );
+ m_Background->StartVideo( path );
}
else if ( m_Lyrics->HasBackground() && g_advancedSettings.m_karaokeAlwaysEmptyOnCdgs )
{
View
1  xbmc/music/karaoke/Makefile.in
@@ -8,6 +8,7 @@ SRCS=GUIDialogKaraokeSongSelector.cpp \
karaokelyricstextkar.cpp \
karaokelyricstextlrc.cpp \
karaokelyricstextustar.cpp \
+ karaokevideobackground.cpp \
karaokewindowbackground.cpp \
LIB=karaoke.a
View
189 xbmc/music/karaoke/karaokevideobackground.cpp
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2005-2010 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "karaokevideobackground.h"
+
+#include "guilib/Texture.h"
+#include "guilib/GUITexture.h"
+#include "settings/Settings.h"
+#include "Application.h"
+#include "DllAvFormat.h"
+#include "DllAvCodec.h"
+#include "DllAvUtil.h"
+#include "DllSwScale.h"
+#include "filesystem/SpecialProtocol.h"
+#include "settings/AdvancedSettings.h"
+#include "video/FFmpegVideoDecoder.h"
+#include "system.h"
+
+KaraokeVideoBackground::KaraokeVideoBackground()
+{
+ m_decoder = new FFmpegVideoDecoder();
+ m_timeFromPrevSong = 0.0;
+ m_texture = 0;
+}
+
+KaraokeVideoBackground::~KaraokeVideoBackground()
+{
+ delete m_decoder;
+ delete m_texture;
+}
+
+bool KaraokeVideoBackground::openVideoFile( const CStdString& filename )
+{
+ CStdString realPath = CSpecialProtocol::TranslatePath( filename );
+
+ if ( !m_decoder->open( realPath ) )
+ {
+ CLog::Log( LOGERROR, "Karaoke Video Background: %s, video file %s (%s)", m_decoder->getErrorMsg().c_str(), filename.c_str(), realPath.c_str() );
+ return false;
+ }
+
+ m_videoWidth = m_decoder->getWidth();
+ m_videoHeight = m_decoder->getHeight();
+ m_curVideoFile = filename;
+
+ // Find out the necessary aspect ratio for height (assuming fit by width) and width (assuming fit by height)
+ RESOLUTION res = g_graphicsContext.GetVideoResolution();
+ m_displayLeft = g_settings.m_ResInfo[res].Overscan.left;
+ m_displayRight = g_settings.m_ResInfo[res].Overscan.right;
+ m_displayTop = g_settings.m_ResInfo[res].Overscan.top;
+ m_displayBottom = g_settings.m_ResInfo[res].Overscan.bottom;
+
+ int screen_width = m_displayRight - m_displayLeft;
+ int screen_height = m_displayBottom - m_displayTop;
+
+ // Do we need to modify the output video size? This could happen in two cases:
+ // 1. Either video dimension is larger than the screen - video needs to be downscaled
+ // 2. Both video dimensions are smaller than the screen - video needs to be upscaled
+ if ( (m_videoWidth > screen_width || m_videoHeight > screen_height )
+ || ( m_videoWidth < screen_width && m_videoHeight < screen_height ) )
+ {
+ // Calculate the scale coefficients for width/height separately
+ double scale_width = (double) screen_width / (double) m_videoWidth;
+ double scale_height = (double) screen_height / (double) m_videoHeight;
+
+ // And apply the smallest
+ double scale = scale_width < scale_height ? scale_width : scale_height;
+ m_videoWidth = (int) (m_videoWidth * scale);
+ m_videoHeight = (int) (m_videoHeight * scale);
+ }
+
+ // Calculate the desktop dimensions to show the video
+ if ( m_videoWidth < screen_width || m_videoHeight < screen_height )
+ {
+ m_displayLeft = (screen_width - m_videoWidth) / 2;
+ m_displayRight -= m_displayLeft;
+
+ m_displayTop = (screen_height - m_videoHeight) / 2;
+ m_displayBottom -= m_displayTop;
+ }
+
+ m_millisecondsPerFrame = 1.0 / m_decoder->getFramesPerSecond();
+
+ CLog::Log( LOGDEBUG, "Karaoke Video Background: Video file %s (%dx%d) length %g seconds opened successfully, will be shown as %dx%d at (%d, %d - %d, %d) rectangle",
+ filename.c_str(),
+ m_decoder->getWidth(), m_decoder->getHeight(),
+ m_decoder->getDuration(),
+ m_videoWidth, m_videoHeight,
+ m_displayLeft, m_displayTop, m_displayRight, m_displayBottom );
+
+ return true;
+}
+
+void KaraokeVideoBackground::closeVideoFile()
+{
+ m_decoder->close();
+}
+
+void KaraokeVideoBackground::Render()
+{
+ // Just in case
+ if ( !m_texture )
+ return;
+
+ // Get the current song timing in ms.
+ // This will only fit songs up to 71,000 hours, so if you got a larger one, change to int64
+ double current = g_application.GetTime();
+
+ // We're supposed to show m_decoder->getFramesPerSecond() frames in one second.
+ if ( current >= m_nextFrameTime )
+ {
+ // We don't care to adjust for the exact timing as we don't worry about the exact frame rate
+ m_nextFrameTime = current + m_millisecondsPerFrame - (current - m_nextFrameTime);
+
+ while ( true )
+ {
+ if ( !m_decoder->nextFrame( m_texture ) )
+ {
+ // End of video; restart
+ m_decoder->seek( 0.0 );
+ m_nextFrameTime = 0.0;
+ continue;
+ }
+
+ break;
+ }
+ }
+
+ // We got a frame. Draw it.
+ CRect vertCoords((float) m_displayLeft, (float) m_displayTop, (float) m_displayRight, (float) m_displayBottom );
+ CGUITexture::DrawQuad(vertCoords, 0xffffffff, m_texture );
+}
+
+bool KaraokeVideoBackground::Start( const CStdString& filename )
+{
+ if ( !filename.empty() )
+ {
+ if ( !openVideoFile( filename ) )
+ return false;
+
+ m_timeFromPrevSong = 0;
+ }
+ else
+ {
+ if ( !openVideoFile( g_advancedSettings.m_karaokeDefaultBackgroundFilePath ) )
+ return false;
+
+ if ( m_timeFromPrevSong != 0.0 && !m_decoder->seek( m_timeFromPrevSong ) )
+ m_timeFromPrevSong = 0;
+ }
+
+ // Allocate the texture
+ m_texture = new CTexture( m_videoWidth, m_videoHeight, XB_FMT_A8R8G8B8 );
+
+ if ( !m_texture )
+ {
+ CLog::Log( LOGERROR, "Karaoke Video Background: Could not allocate texture" );
+ return false;
+ }
+
+ m_nextFrameTime = 0.0;
+ return true;
+}
+
+void KaraokeVideoBackground::Stop()
+{
+ delete m_texture;
+ m_texture = 0;
+
+ m_timeFromPrevSong = m_decoder->getLastFrameTime();
+}
View
86 xbmc/music/karaoke/karaokevideobackground.h
@@ -0,0 +1,86 @@
+#ifndef KARAOKEVIDEOFFMPEG_H
+#define KARAOKEVIDEOFFMPEG_H
+
+/*
+ * Copyright (C) 2005-2010 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "utils/StdString.h"
+
+class CBaseTexture;
+class FFmpegVideoDecoder;
+
+// C++ Interface: karaokevideoffmpeg
+// Contact: oldnemesis
+//
+// FFMpeg-based background video decoder for Karaoke background.
+// We are not using DVDPlayer for this because:
+// 1. DVDPlayer was not designed to run at the same time when music is being played and other things (like lyrics) rendered.
+// While this setup works from time to time, it constantly gets broken. Some modes, like VDPAU, lead to crash right away.
+//
+// 2. We do not need to decode audio, hence we don't have to use extra CPU.
+//
+// 3. We do not really care about frame rate. Jerky video is fine for the background. Lyrics sync is much more important.
+//
+class KaraokeVideoBackground
+{
+public:
+ KaraokeVideoBackground();
+ ~KaraokeVideoBackground();
+
+ // Start playing the video. It is called each time a new song is being played. Should continue playing existing
+ // video from the position it was paused. If it returns false, the video rendering is disabled and
+ // KaraokeVideoFFMpeg object is deleted. Must write the reason for failure into the log file.
+ bool Start( const CStdString& filename = "" );
+
+ // Render the current frame into the screen. This function also must handle video loops and
+ // switching to the next video when necessary. Hence it shouldn't take too long.
+ void Render();
+
+ // Stops playing the video. It is called once the song is finished and the Render() is not going to be called anymore.
+ // The object, however, is kept and should keep its state because it must continue on next Start() call.
+ void Stop();
+
+private:
+ // Initialize the object. This function is called only once when the object is created or after it has been dismissed.
+ // If it returns false, the video rendering is disabled and KaraokeVideoFFMpeg object is deleted
+ bool Init();
+
+ // Dismisses the object, freeing all the memory and unloading the libraries. The object must be inited before using again.
+ void Dismiss();
+
+ bool openVideoFile( const CStdString& filename );
+ void closeVideoFile();
+
+ // FFMpeg objects
+ FFmpegVideoDecoder * m_decoder;
+
+ CStdString m_curVideoFile;
+ int m_videoWidth; // shown video width, i.e. upscaled or downscaled as necessary
+ int m_videoHeight; // shown video height, i.e. upscaled or downscaled as necessary
+ int m_displayLeft, m_displayRight, m_displayTop, m_displayBottom; // Video as shown at the display
+ double m_millisecondsPerFrame;
+ double m_nextFrameTime;
+ double m_timeFromPrevSong;
+
+ CBaseTexture *m_texture;
+};
+
+#endif
View
125 xbmc/music/karaoke/karaokewindowbackground.cpp
@@ -28,11 +28,11 @@
#include "GUIUserMessages.h"
#include "guilib/GUIVisualisationControl.h"
#include "guilib/GUIImage.h"
-#include "cores/dvdplayer/DVDPlayer.h"
#include "threads/SingleLock.h"
#include "utils/log.h"
#include "karaokewindowbackground.h"
+#include "karaokevideobackground.h"
#define CONTROL_ID_VIS 1
@@ -50,19 +50,13 @@ CKaraokeWindowBackground::CKaraokeWindowBackground()
m_videoPlayer = 0;
m_parentWindow = 0;
- m_videoLastTime = 0;
- m_playingDefaultVideo = false;
- m_videoEnded = false;
}
CKaraokeWindowBackground::~CKaraokeWindowBackground()
{
if ( m_videoPlayer )
- {
- m_videoPlayer->CloseFile();
- delete m_videoPlayer;
- }
+ delete m_videoPlayer;
}
@@ -95,7 +89,6 @@ void CKaraokeWindowBackground::Init(CGUIWindow * wnd)
{
CLog::Log( LOGDEBUG, "Karaoke default background is video %s", g_advancedSettings.m_karaokeDefaultBackgroundFilePath.c_str() );
m_defaultMode = BACKGROUND_VIDEO;
- m_path = g_advancedSettings.m_karaokeDefaultBackgroundFilePath;
}
}
@@ -141,31 +134,12 @@ bool CKaraokeWindowBackground::OnMessage(CGUIMessage & message)
void CKaraokeWindowBackground::Render()
{
- // We cannot use CSingleLock on m_CritSectionVideoEnded, because OnPlayBackEnded() might be
- // called from a different thread, and since we cannot proceed on m_CritSectionShared, we'll deadlock
- bool ended;
- {
- CSingleLock lock( m_CritSectionVideoEnded );
- ended = m_videoEnded;
- }
-
CSingleLock lock (m_CritSectionShared);
- // Do we need to restart video?
- if ( ended )
- {
- NextVideo();
- return; // VERY important! Player thread is locked now, and if we continue, we'll lock in g_renderManager.Present()
- }
// Proceed with video rendering
- if ( m_currentMode == BACKGROUND_VIDEO )
+ if ( m_currentMode == BACKGROUND_VIDEO && m_videoPlayer )
{
-#ifdef HAS_VIDEO_PLAYBACK
- if ( g_application.IsPresentFrame() )
- g_renderManager.Present();
- else
- g_renderManager.RenderUpdate(true, 0, 255);
-#endif
+ m_videoPlayer->Render();
}
// For other visualisations just disable the screen saver
@@ -206,44 +180,19 @@ void CKaraokeWindowBackground::StartImage( const CStdString& path )
}
-void CKaraokeWindowBackground::StartVideo( const CStdString& path, int64_t offset)
+void CKaraokeWindowBackground::StartVideo( const CStdString& path )
{
- CFileItem item( path, false);
- m_videoEnded = false;
-
- // Video options
- CPlayerOptions options;
- options.video_only = true;
-
- if ( offset > 0 )
- options.starttime = (double) (offset / 1000.0);
-
- if ( !item.IsVideo() )
- {
- CLog::Log(LOGERROR, "KaraokeVideoBackground: file %s is not a video file, ignoring", path.c_str() );
- return;
- }
-
- if ( item.IsDVD() )
- {
- CLog::Log(LOGERROR, "KaraokeVideoBackground: DVD video playback is not supported");
- return;
- }
-
if ( !m_videoPlayer )
- m_videoPlayer = new CDVDPlayer(*this);
+ m_videoPlayer = new KaraokeVideoBackground();
- if ( !m_videoPlayer )
- return;
-
- if ( !m_videoPlayer->OpenFile( item, options ) )
+ if ( !m_videoPlayer->Start( path ) )
{
- CLog::Log(LOGERROR, "KaraokeVideoBackground: error opening video file %s", item.GetPath().c_str());
+ delete m_videoPlayer;
+ m_videoPlayer = 0;
+ m_currentMode = BACKGROUND_NONE;
return;
}
-
- CLog::Log(LOGDEBUG, "KaraokeVideoBackground: video file %s opened successfully", item.GetPath().c_str());
-
+
m_ImgControl->SetVisible( false );
m_VisControl->SetVisible( false );
m_currentMode = BACKGROUND_VIDEO;
@@ -267,10 +216,7 @@ void CKaraokeWindowBackground::StartDefault()
break;
case BACKGROUND_VIDEO:
- StartVideo( m_path, m_videoLastTime );
-
- if ( m_currentMode == BACKGROUND_VIDEO )
- m_playingDefaultVideo = true;
+ StartVideo();
break;
default:
@@ -285,16 +231,8 @@ void CKaraokeWindowBackground::Stop()
CSingleLock lock (m_CritSectionShared);
m_currentMode = BACKGROUND_NONE;
- // Disable and hide all control
if ( m_videoPlayer )
- {
- if ( m_playingDefaultVideo )
- m_videoLastTime = m_videoPlayer->GetTime();
-
- m_videoPlayer->CloseFile();
- delete m_videoPlayer;
- m_videoPlayer = 0;
- }
+ m_videoPlayer->Stop();
CLog::Log( LOGDEBUG, "Karaoke background stopped" );
}
@@ -302,57 +240,20 @@ void CKaraokeWindowBackground::Stop()
void CKaraokeWindowBackground::OnPlayBackEnded()
{
- CSingleLock lock ( m_CritSectionVideoEnded );
- m_videoEnded = true;
-/* CSingleLock lock (m_CritSectionShared);
-
- CLog::Log( LOGDEBUG, "KaraokeVideoBackground: stopping" );
- Stop();
- CLog::Log( LOGDEBUG, "KaraokeVideoBackground: stopped" );
- m_videoLastTime = 0;
- StartVideo( m_path, m_videoLastTime );
- CLog::Log( LOGDEBUG, "KaraokeVideoBackground: restarting video from the beginning" );
-*/
}
-
void CKaraokeWindowBackground::OnPlayBackStarted()
{
}
-
void CKaraokeWindowBackground::OnPlayBackStopped()
{
}
-
void CKaraokeWindowBackground::OnQueueNextItem()
{
}
void CKaraokeWindowBackground::Pause(bool now_paused)
{
- if ( m_currentMode == BACKGROUND_VIDEO && m_videoPlayer )
- {
- if ( (now_paused && !m_videoPlayer->IsPaused())
- || ( !now_paused && m_videoPlayer->IsPaused() ) )
- m_videoPlayer->Pause();
- }
-}
-
-void CKaraokeWindowBackground::NextVideo()
-{
- // This function should not be called directly from the callback! Deadlock!!!
- m_videoPlayer->CloseFile();
-
- // Only one video selected, restarting
- m_videoLastTime = 0;
-
- {
- CSingleLock lock(m_CritSectionVideoEnded );
- m_videoEnded = false;
- }
-
- StartVideo( m_path, m_videoLastTime );
- CLog::Log( LOGDEBUG, "KaraokeVideoBackground: restarting video from the beginning" );
}
View
18 xbmc/music/karaoke/karaokewindowbackground.h
@@ -29,7 +29,7 @@
class CGUIWindow;
class CGUIImage;
class CGUIVisualisationControl;
-class CDVDPlayer;
+class KaraokeVideoBackground;
class CKaraokeWindowBackground : public IPlayerCallback
{
@@ -49,7 +49,7 @@ class CKaraokeWindowBackground : public IPlayerCallback
virtual void StartImage( const CStdString& path );
// Start with song-specific video background
- virtual void StartVideo( const CStdString& path, int64_t offset = 0 );
+ virtual void StartVideo( const CStdString& path = "" );
// Start with default (setting-specific) background
virtual void StartDefault();
@@ -60,9 +60,6 @@ class CKaraokeWindowBackground : public IPlayerCallback
// Stop any kind of background
virtual void Stop();
- // Switch to next video, or restart current one
- virtual void NextVideo();
-
// Function forwarders
virtual bool OnAction(const CAction &action);
virtual bool OnMessage(CGUIMessage& message);
@@ -86,10 +83,6 @@ class CKaraokeWindowBackground : public IPlayerCallback
// This critical section protects all variables except m_videoEnded
CCriticalSection m_CritSectionShared;
- // This critical section protects m_videoEnded, since it could be changed from a different thread
- // while the section above is locked
- CCriticalSection m_CritSectionVideoEnded;
-
// for visualization background
CGUIVisualisationControl * m_VisControl;
CGUIImage * m_ImgControl;
@@ -100,14 +93,11 @@ class CKaraokeWindowBackground : public IPlayerCallback
CGUIWindow * m_parentWindow;
// Video player pointer
- CDVDPlayer * m_videoPlayer;
- bool m_videoEnded;
+ KaraokeVideoBackground * m_videoPlayer;
// For default visualisation mode
BackgroundMode m_defaultMode;
- CStdString m_path; // image or video
- int64_t m_videoLastTime; // video only
- bool m_playingDefaultVideo; // whether to store the time
+ CStdString m_path; // image
};
#endif
View
324 xbmc/video/FFmpegVideoDecoder.cpp
@@ -0,0 +1,324 @@
+/*
+ * Copyright (C) 2005-2012 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "system.h"
+#include "DllAvFormat.h"
+#include "DllAvCodec.h"
+#include "DllAvUtil.h"
+#include "DllSwScale.h"
+#include "guilib/Texture.h"
+
+#include "FFmpegVideoDecoder.h"
+
+
+FFmpegVideoDecoder::FFmpegVideoDecoder()
+{
+ m_pFormatCtx = 0;
+ m_pCodecCtx = 0;
+ m_pCodec = 0;
+ m_pFrame = 0;
+ m_pFrameRGB = 0;
+
+ m_dllAvFormat = new DllAvFormat();
+ m_dllAvCodec = new DllAvCodec();
+ m_dllAvUtil = new DllAvUtil();
+ m_dllSwScale = new DllSwScale();
+}
+
+FFmpegVideoDecoder::~FFmpegVideoDecoder()
+{
+ close();
+
+ delete m_dllAvFormat;
+ delete m_dllAvCodec;
+ delete m_dllAvUtil;
+ delete m_dllSwScale;
+}
+
+void FFmpegVideoDecoder::close()
+{
+ // Free the YUV frame
+ if ( m_pFrame )
+ m_dllAvUtil->av_free( m_pFrame );
+
+ // Free the RGB frame
+ if ( m_pFrameRGB )
+ {
+ m_dllAvCodec->avpicture_free( m_pFrameRGB );
+ m_dllAvUtil->av_free( m_pFrameRGB );
+ }
+
+ // Close the codec
+ if ( m_pCodecCtx )
+ m_dllAvCodec->avcodec_close( m_pCodecCtx );
+
+ // Close the video file
+ if ( m_pFormatCtx )
+ m_dllAvFormat->avformat_close_input( &m_pFormatCtx );
+
+ m_pFormatCtx = 0;
+ m_pCodecCtx = 0;
+ m_pCodec = 0;
+ m_pFrame = 0;
+ m_pFrameRGB = 0;
+
+ if ( m_dllAvCodec->IsLoaded() )
+ m_dllAvCodec->Unload();
+
+ if ( m_dllAvUtil->IsLoaded() )
+ m_dllAvUtil->Unload();
+
+ if ( m_dllSwScale->IsLoaded() )
+ m_dllSwScale->Unload();
+
+ if ( m_dllAvFormat->IsLoaded() )
+ m_dllAvFormat->Unload();
+}
+
+bool FFmpegVideoDecoder::isOpened() const
+{
+ return m_pFrame ? true : false;
+}
+
+double FFmpegVideoDecoder::getDuration() const
+{
+ if ( m_pFormatCtx && m_pFormatCtx->duration / AV_TIME_BASE > 0.0 )
+ return m_pFormatCtx->duration / AV_TIME_BASE;
+
+ return 0.0;
+}
+
+double FFmpegVideoDecoder::getFramesPerSecond() const
+{
+ return m_pFormatCtx ? av_q2d( m_pFormatCtx->streams[ m_videoStream ]->r_frame_rate ) : 0.0;
+}
+
+unsigned int FFmpegVideoDecoder::getWidth() const
+{
+ if ( !m_pCodecCtx )
+ return 0;
+
+ return m_pCodecCtx->width;
+}
+
+unsigned int FFmpegVideoDecoder::getHeight() const
+{
+ if ( !m_pCodecCtx )
+ return 0;
+
+ return m_pCodecCtx->height;
+}
+
+const AVFormatContext * FFmpegVideoDecoder::getAVFormatContext() const
+{
+ return m_pFormatCtx;
+}
+
+const AVCodecContext * FFmpegVideoDecoder::getAVCodecContext() const
+{
+ return m_pCodecCtx;
+}
+
+const AVCodec * FFmpegVideoDecoder::getAVCodec() const
+{
+ return m_pCodec;
+}
+
+CStdString FFmpegVideoDecoder::getErrorMsg() const
+{
+ return m_errorMsg;
+}
+
+double FFmpegVideoDecoder::getLastFrameTime() const
+{
+ return m_lastFrameTime;
+}
+
+
+bool FFmpegVideoDecoder::open( const CStdString& filename )
+{
+ // See http://dranger.com/ffmpeg/tutorial01.html
+ close();
+
+ if ( !m_dllAvUtil->Load() || !m_dllAvCodec->Load() || !m_dllSwScale->Load() || !m_dllAvFormat->Load() )
+ {
+ m_errorMsg = "Failed to load FFMpeg libraries";
+ return false;
+ }
+
+ m_dllAvCodec->avcodec_register_all();
+ m_dllAvFormat->av_register_all();
+
+ // Open the video file
+ if ( m_dllAvFormat->avformat_open_input( &m_pFormatCtx, filename.c_str(), NULL, NULL ) < 0 )
+ {
+ m_errorMsg = "Could not open the video file";
+ close();
+ return false;
+ }
+
+ // Retrieve the stream information
+ if ( m_dllAvFormat->avformat_find_stream_info( m_pFormatCtx, 0 ) < 0 )
+ {
+ m_errorMsg = "Could not find the stream information";
+ close();
+ return false;
+ }
+
+ // Find the first video stream
+ m_videoStream = -1;
+
+ for ( unsigned i = 0; i < m_pFormatCtx->nb_streams; i++ )
+ {
+ if ( m_pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO )
+ {
+ m_videoStream = i;
+ break;
+ }
+ }
+
+ if ( m_videoStream == -1 )
+ {
+ m_errorMsg = "Could not find a playable video stream";
+ close();
+ return false;
+ }
+
+ // Get a pointer to the codec context for the video stream
+ m_pCodecCtx = m_pFormatCtx->streams[ m_videoStream ]->codec;
+
+ // Find the decoder for the video stream
+ m_pCodec = m_dllAvCodec->avcodec_find_decoder( m_pCodecCtx->codec_id );
+
+ if ( m_pCodec == NULL )
+ {
+ m_errorMsg = "Could not find a video decoder";
+ close();
+ return false;
+ }
+
+ // Open the codec
+ if ( m_dllAvCodec->avcodec_open2( m_pCodecCtx, m_pCodec, 0 ) < 0 )
+ {
+ m_errorMsg = "Could not open the video decoder";
+ close();
+ return false;
+ }
+
+ // Allocate video frames
+ m_pFrame = m_dllAvCodec->avcodec_alloc_frame();
+
+ if ( !m_pFrame )
+ {
+ m_errorMsg = "Could not allocate memory for a frame";
+ close();
+ return false;
+ }
+
+ return true;
+}
+
+
+bool FFmpegVideoDecoder::seek( double time )
+{
+ // Convert the frame number into time stamp
+ int64_t timestamp = (int64_t) (time * AV_TIME_BASE * av_q2d( m_pFormatCtx->streams[ m_videoStream ]->time_base ));
+
+ if ( m_dllAvFormat->av_seek_frame( m_pFormatCtx, m_videoStream, timestamp, AVSEEK_FLAG_ANY ) < 0 )
+ return false;
+
+ m_dllAvCodec->avcodec_flush_buffers( m_pCodecCtx );
+ return true;
+}
+
+bool FFmpegVideoDecoder::nextFrame( CBaseTexture * texture )
+{
+ // Just in case
+ if ( !m_pCodecCtx )
+ return false;
+
+ // If we did not preallocate the picture or the texture size changed, (re)allocate it
+ if ( !m_pFrameRGB || texture->GetWidth() != m_frameRGBwidth || texture->GetHeight() != m_frameRGBheight )
+ {
+ if ( m_pFrameRGB )
+ {
+ m_dllAvCodec->avpicture_free( m_pFrameRGB );
+ m_dllAvUtil->av_free( m_pFrameRGB );
+ }
+
+ m_frameRGBwidth = texture->GetWidth();
+ m_frameRGBheight = texture->GetHeight();
+
+ // Allocate the conversion frame and relevant picture
+ m_pFrameRGB = (AVPicture*)m_dllAvUtil->av_mallocz(sizeof(AVPicture));
+
+ if ( !m_pFrameRGB )
+ return false;
+
+ // Due to a bug in swsscale we need to allocate one extra line of data
+ if ( m_dllAvCodec->avpicture_alloc( m_pFrameRGB, PIX_FMT_RGB32, m_frameRGBwidth, m_frameRGBheight + 1 ) < 0 )
+ return false;
+ }
+
+ AVPacket packet;
+ int frameFinished;
+
+ while ( true )
+ {
+ // Read a frame
+ if ( m_dllAvFormat->av_read_frame( m_pFormatCtx, &packet ) < 0 )
+ return false; // Frame read failed (e.g. end of stream)
+
+ if ( packet.stream_index == m_videoStream )
+ {
+ // Is this a packet from the video stream -> decode video frame
+ m_dllAvCodec->avcodec_decode_video2( m_pCodecCtx, m_pFrame, &frameFinished, &packet );
+
+ // Did we get a video frame?
+ if ( frameFinished )
+ {
+ if ( packet.dts != AV_NOPTS_VALUE )
+ m_lastFrameTime = packet.dts * av_q2d( m_pFormatCtx->streams[ m_videoStream ]->time_base );
+ else
+ m_lastFrameTime = 0.0;
+
+ break;
+ }
+ }
+
+ m_dllAvCodec->av_free_packet( &packet );
+ }
+
+ // We got the video frame, render it into the picture buffer
+ struct SwsContext * context = m_dllSwScale->sws_getContext( m_pCodecCtx->width, m_pCodecCtx->height, m_pCodecCtx->pix_fmt,
+ m_frameRGBwidth, m_frameRGBheight, PIX_FMT_RGB32, SWS_FAST_BILINEAR, NULL, NULL, NULL );
+
+ m_dllSwScale->sws_scale( context, m_pFrame->data, m_pFrame->linesize, 0, m_pCodecCtx->height,
+ m_pFrameRGB->data, m_pFrameRGB->linesize );
+ m_dllSwScale->sws_freeContext( context );
+ m_dllAvCodec->av_free_packet( &packet );
+
+ // And into the texture
+ texture->Update( m_frameRGBwidth, m_frameRGBheight, m_frameRGBwidth * 4, XB_FMT_A8R8G8B8, m_pFrameRGB->data[0], false );
+
+ return true;
+}
+
View
164 xbmc/video/FFmpegVideoDecoder.h
@@ -0,0 +1,164 @@
+#ifndef FFMPEGVIDEODECODER_H
+#define FFMPEGVIDEODECODER_H
+
+/*
+ * Copyright (C) 2005-2012 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "utils/StdString.h"
+
+class CBaseTexture;
+class m_dllAvFormat;
+class m_dllAvCodec;
+class m_dllAvUtil;
+class m_dllSwScale;
+
+struct AVFormatContext;
+struct AVCodecContext;
+struct AVCodec;
+struct AVFrame;
+
+/**
+ * A simple FFMpeg-based background video decoder.
+ *
+ * This class only decodes the video using the standard FFmpeg calls, so likely no hardware acceleration.
+ * No audio decoding, and no rendering.
+ *
+ */
+class FFmpegVideoDecoder
+{
+public:
+ FFmpegVideoDecoder();
+ ~FFmpegVideoDecoder();
+
+ /**
+ * Opens the video file for decoding. Supports all the formats supported by the used FFmpeg.
+ * The file must have at least one video track. If it has more than one, the first video track
+ * would be decoded.
+ *
+ * If an existing stream was opened, it is automatically closed and the new stream is opened.
+ *
+ * Returns true if the file was opened successfully, and false otherwise, in which case
+ * the getErrorMsg() function could be used to retrieve the reason.
+ *
+ * @param filename The video file name, which must be translated through CSpecialProtocol::TranslatePath()
+ */
+ bool open( const CStdString& filename );
+
+ /**
+ * Returns true if the decoder has the video file opened.
+ */
+ bool isOpened() const;
+
+ /**
+ * Returns the movie duration in seconds or 0.0 if the duration is not available. For some formats
+ * is calculated through the heuristics, and the video might not really be that long (for example if it is incomplete).
+ * The total number of frames is calculated by multiplying the duration by getFramesPerSecond()
+ */
+ double getDuration() const;
+
+ /**
+ * Returns the frames per second for this video
+ */
+ double getFramesPerSecond() const;
+
+ /**
+ * Returns the original video width or 0 if the video wasn't opened.
+ */
+ unsigned int getWidth() const;
+
+ /**
+ * Returns the original video height or 0 if the video wasn't opened.
+ */
+ unsigned int getHeight() const;
+
+ /**
+ * Returns the last rendered frame number.
+ */
+ double getLastFrameTime() const;
+
+ /**
+ * Returns the AVFormatContext structure associated with this video format
+ */
+ const AVFormatContext * getAVFormatContext() const;
+
+ /**
+ * Returns the AVCodecContext structure associated with this video codec
+ */
+ const AVCodecContext * getAVCodecContext() const;
+
+ /**
+ * Returns the AVCodec structure associated with this video codec
+ */
+ const AVCodec * getAVCodec() const;
+
+ /**
+ * Returns the error message text if opening the video failed
+ */
+ CStdString getErrorMsg() const;
+
+ /**
+ * Decodes and renders the next video frame into the provided texture which
+ * must be in a XB_FMT_A8R8G8B8 format.
+ * The frame will be rescaled to fit the whole texture (i.e. texture width/height)
+ * so make sure the texture aspect ratio is the same as in the original movie.
+ *
+ * @param texture The texture to render the frame into. Must be preallocated,
+ * have the appropriate width/height and in XB_FMT_A8R8G8B8 format.
+ *
+ * @return true if the frame rendered, false if there are no more frames
+ */
+ bool nextFrame( CBaseTexture * texture );
+
+ /**
+ * Seeks to a specific time position in the video file. Note that the seek is limited to the keyframes only.
+ * @param time The time to seek to, in seconds
+ * @return true if the seek succeed, false if failed
+ */
+ bool seek( double time );
+
+ /**
+ * Closes the video stream.
+ */
+ void close();
+
+private:
+ bool readFrame( int frame );
+
+ DllAvFormat *m_dllAvFormat;
+ DllAvCodec *m_dllAvCodec;
+ DllAvUtil *m_dllAvUtil;
+ DllSwScale *m_dllSwScale;
+ AVFormatContext *m_pFormatCtx;
+ AVCodecContext *m_pCodecCtx;
+ AVCodec *m_pCodec;
+ AVFrame *m_pFrame;
+ AVPicture *m_pFrameRGB;
+ int m_videoStream;
+ double m_lastFrameTime;
+
+ // The dimensions of the allocated pFrameRGB
+ unsigned int m_frameRGBwidth;
+ unsigned int m_frameRGBheight;
+
+ CStdString m_errorMsg;
+};
+
+#endif
View
1  xbmc/video/Makefile
@@ -1,4 +1,5 @@
SRCS=Bookmark.cpp \
+ FFmpegVideoDecoder.cpp \
GUIViewStateVideo.cpp \
Teletext.cpp \
VideoDatabase.cpp \
Something went wrong with that request. Please try again.