2017-01-25 15:00:56 +00:00
|
|
|
#ifdef _RPI_
|
|
|
|
#include "components/VideoPlayerComponent.h"
|
2017-11-01 22:21:10 +00:00
|
|
|
|
2017-11-29 19:57:43 +00:00
|
|
|
#include "utils/StringUtil.h"
|
2017-06-02 15:58:44 +00:00
|
|
|
#include "AudioManager.h"
|
2018-01-19 01:09:49 +00:00
|
|
|
#include "Renderer.h"
|
2017-03-25 17:02:28 +00:00
|
|
|
#include "Settings.h"
|
2017-01-25 15:00:56 +00:00
|
|
|
#include <fcntl.h>
|
2018-01-29 22:50:10 +00:00
|
|
|
#include <unistd.h>
|
2017-11-01 22:21:10 +00:00
|
|
|
#include <wait.h>
|
2017-08-22 19:34:59 +00:00
|
|
|
|
|
|
|
class VolumeControl
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
static std::shared_ptr<VolumeControl> & getInstance();
|
|
|
|
int getVolume() const;
|
|
|
|
};
|
2017-01-25 15:00:56 +00:00
|
|
|
|
2017-06-01 20:08:44 +00:00
|
|
|
VideoPlayerComponent::VideoPlayerComponent(Window* window, std::string path) :
|
2017-01-25 15:00:56 +00:00
|
|
|
VideoComponent(window),
|
2017-06-01 20:08:44 +00:00
|
|
|
mPlayerPid(-1),
|
|
|
|
subtitlePath(path)
|
2017-01-25 15:00:56 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
VideoPlayerComponent::~VideoPlayerComponent()
|
|
|
|
{
|
2016-12-14 08:30:54 +00:00
|
|
|
stopVideo();
|
2017-01-25 15:00:56 +00:00
|
|
|
}
|
|
|
|
|
2017-10-28 20:24:35 +00:00
|
|
|
void VideoPlayerComponent::render(const Transform4x4f& parentTrans)
|
2017-01-25 15:00:56 +00:00
|
|
|
{
|
|
|
|
VideoComponent::render(parentTrans);
|
2017-06-13 22:57:18 +00:00
|
|
|
|
|
|
|
if (!mIsPlaying || mPlayerPid == -1)
|
|
|
|
VideoComponent::renderSnapshot(parentTrans);
|
2017-01-25 15:00:56 +00:00
|
|
|
}
|
|
|
|
|
2017-03-25 17:02:28 +00:00
|
|
|
void VideoPlayerComponent::setResize(float width, float height)
|
|
|
|
{
|
|
|
|
setSize(width, height);
|
2017-10-28 23:19:19 +00:00
|
|
|
mTargetSize = Vector2f(width, height);
|
2017-03-25 17:02:28 +00:00
|
|
|
mTargetIsMax = false;
|
|
|
|
mStaticImage.setSize(width, height);
|
|
|
|
onSizeChanged();
|
|
|
|
}
|
|
|
|
|
|
|
|
void VideoPlayerComponent::setMaxSize(float width, float height)
|
|
|
|
{
|
|
|
|
setSize(width, height);
|
2017-10-28 23:19:19 +00:00
|
|
|
mTargetSize = Vector2f(width, height);
|
2017-03-25 17:02:28 +00:00
|
|
|
mTargetIsMax = true;
|
|
|
|
mStaticImage.setMaxSize(width, height);
|
|
|
|
onSizeChanged();
|
|
|
|
}
|
|
|
|
|
2017-01-25 15:00:56 +00:00
|
|
|
void VideoPlayerComponent::startVideo()
|
|
|
|
{
|
2017-06-01 20:08:44 +00:00
|
|
|
if (!mIsPlaying)
|
|
|
|
{
|
2017-01-25 15:00:56 +00:00
|
|
|
mVideoWidth = 0;
|
|
|
|
mVideoHeight = 0;
|
|
|
|
|
|
|
|
std::string path(mVideoPath.c_str());
|
|
|
|
|
|
|
|
// Make sure we have a video path
|
|
|
|
if ((path.size() > 0) && (mPlayerPid == -1))
|
|
|
|
{
|
|
|
|
// Set the video that we are going to be playing so we don't attempt to restart it
|
|
|
|
mPlayingVideoPath = mVideoPath;
|
|
|
|
|
2017-06-01 20:08:44 +00:00
|
|
|
// Disable AudioManager so video can play, in case we're requesting ALSA
|
2017-11-29 19:57:43 +00:00
|
|
|
if (Utils::String::startsWith(Settings::getInstance()->getString("OMXAudioDev").c_str(), "alsa"))
|
2017-06-01 20:08:44 +00:00
|
|
|
{
|
|
|
|
AudioManager::getInstance()->deinit();
|
|
|
|
}
|
2017-06-02 15:58:44 +00:00
|
|
|
|
2017-01-25 15:00:56 +00:00
|
|
|
// Start the player process
|
|
|
|
pid_t pid = fork();
|
|
|
|
if (pid == -1)
|
|
|
|
{
|
|
|
|
// Failed
|
|
|
|
mPlayingVideoPath = "";
|
|
|
|
}
|
|
|
|
else if (pid > 0)
|
|
|
|
{
|
|
|
|
mPlayerPid = pid;
|
|
|
|
// Update the playing state
|
2017-03-25 17:02:28 +00:00
|
|
|
signal(SIGCHLD, catch_child);
|
2017-01-25 15:00:56 +00:00
|
|
|
mIsPlaying = true;
|
|
|
|
mFadeIn = 0.0f;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-03-25 17:02:28 +00:00
|
|
|
|
2017-01-25 15:00:56 +00:00
|
|
|
// Find out the pixel position of the video view and build a command line for
|
|
|
|
// omxplayer to position it in the right place
|
2018-01-19 01:09:49 +00:00
|
|
|
char buf1[32];
|
|
|
|
char buf2[32];
|
2017-01-25 15:00:56 +00:00
|
|
|
float x = mPosition.x() - (mOrigin.x() * mSize.x());
|
|
|
|
float y = mPosition.y() - (mOrigin.y() * mSize.y());
|
2018-01-19 01:09:49 +00:00
|
|
|
|
|
|
|
// fix x and y
|
|
|
|
switch(Renderer::getScreenRotate())
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
{
|
|
|
|
const int x1 = (int)(Renderer::getScreenOffsetX() + x);
|
|
|
|
const int y1 = (int)(Renderer::getScreenOffsetY() + y);
|
|
|
|
const int x2 = (int)(x1 + mSize.x());
|
|
|
|
const int y2 = (int)(y1 + mSize.y());
|
|
|
|
sprintf(buf1, "%d,%d,%d,%d", x1, y1, x2, y2);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1:
|
|
|
|
{
|
|
|
|
const int x1 = (int)(Renderer::getScreenOffsetY() + Renderer::getScreenHeight() - y - mSize.y());
|
|
|
|
const int y1 = (int)(Renderer::getScreenOffsetX() + x);
|
|
|
|
const int x2 = (int)(x1 + mSize.y());
|
|
|
|
const int y2 = (int)(y1 + mSize.x());
|
|
|
|
sprintf(buf1, "%d,%d,%d,%d", x1, y1, x2, y2);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
{
|
|
|
|
const int x1 = (int)(Renderer::getScreenOffsetX() + Renderer::getScreenWidth() - x - mSize.x());
|
|
|
|
const int y1 = (int)(Renderer::getScreenOffsetY() + Renderer::getScreenHeight() - y - mSize.y());
|
|
|
|
const int x2 = (int)(x1 + mSize.x());
|
|
|
|
const int y2 = (int)(y1 + mSize.y());
|
|
|
|
sprintf(buf1, "%d,%d,%d,%d", x1, y1, x2, y2);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 3:
|
|
|
|
{
|
|
|
|
const int x1 = (int)(Renderer::getScreenOffsetY() + y);
|
|
|
|
const int y1 = (int)(Renderer::getScreenOffsetX() + Renderer::getScreenWidth() - x - mSize.x());
|
|
|
|
const int x2 = (int)(x1 + mSize.y());
|
|
|
|
const int y2 = (int)(y1 + mSize.x());
|
|
|
|
sprintf(buf1, "%d,%d,%d,%d", x1, y1, x2, y2);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// rotate the video
|
|
|
|
switch(Renderer::getScreenRotate())
|
|
|
|
{
|
|
|
|
case 0: { sprintf(buf2, "%d", (int) 0); } break;
|
|
|
|
case 1: { sprintf(buf2, "%d", (int) 90); } break;
|
|
|
|
case 2: { sprintf(buf2, "%d", (int)180); } break;
|
|
|
|
case 3: { sprintf(buf2, "%d", (int)270); } break;
|
|
|
|
}
|
|
|
|
|
2017-01-25 15:00:56 +00:00
|
|
|
// We need to specify the layer of 10000 or above to ensure the video is displayed on top
|
|
|
|
// of our SDL display
|
2017-03-25 17:02:28 +00:00
|
|
|
|
2018-01-19 01:09:49 +00:00
|
|
|
const char* argv[] = { "", "--layer", "10010", "--loop", "--no-osd", "--aspect-mode", "letterbox", "--vol", "0", "-o", "both","--win", buf1, "--orientation", buf2, "", "", "", "", NULL };
|
2017-03-25 17:02:28 +00:00
|
|
|
|
|
|
|
// check if we want to mute the audio
|
2017-08-22 19:34:59 +00:00
|
|
|
if (!Settings::getInstance()->getBool("VideoAudio") || (float)VolumeControl::getInstance()->getVolume() == 0)
|
2017-03-25 17:02:28 +00:00
|
|
|
{
|
|
|
|
argv[8] = "-1000000";
|
|
|
|
}
|
2017-08-22 19:34:59 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
float percentVolume = (float)VolumeControl::getInstance()->getVolume();
|
2017-10-07 07:58:09 +00:00
|
|
|
int OMXVolume = (int)((percentVolume-98)*105);
|
2017-08-22 19:34:59 +00:00
|
|
|
argv[8] = std::to_string(OMXVolume).c_str();
|
|
|
|
}
|
2017-03-25 17:02:28 +00:00
|
|
|
|
2017-06-01 20:08:44 +00:00
|
|
|
// test if there's a path for possible subtitles, meaning we're a screensaver video
|
|
|
|
if (!subtitlePath.empty())
|
|
|
|
{
|
|
|
|
// if we are rendering a screensaver
|
|
|
|
|
|
|
|
// check if we want to stretch the image
|
|
|
|
if (Settings::getInstance()->getBool("StretchVideoOnScreenSaver"))
|
|
|
|
{
|
|
|
|
argv[6] = "stretch";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Settings::getInstance()->getString("ScreenSaverGameInfo") != "never")
|
|
|
|
{
|
|
|
|
// if we have chosen to render subtitles
|
2018-01-19 01:09:49 +00:00
|
|
|
argv[15] = "--subtitles";
|
|
|
|
argv[16] = subtitlePath.c_str();
|
|
|
|
argv[17] = mPlayingVideoPath.c_str();
|
2017-06-01 20:08:44 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// if we have chosen NOT to render subtitles in the screensaver
|
2018-01-19 01:09:49 +00:00
|
|
|
argv[15] = mPlayingVideoPath.c_str();
|
2017-06-01 20:08:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2017-03-25 17:02:28 +00:00
|
|
|
{
|
2017-06-01 20:08:44 +00:00
|
|
|
// if we are rendering a video gamelist
|
|
|
|
if (!mTargetIsMax)
|
|
|
|
{
|
|
|
|
argv[6] = "stretch";
|
|
|
|
}
|
2018-01-19 01:09:49 +00:00
|
|
|
argv[15] = mPlayingVideoPath.c_str();
|
2017-03-25 17:02:28 +00:00
|
|
|
}
|
|
|
|
|
2017-06-02 15:58:44 +00:00
|
|
|
argv[10] = Settings::getInstance()->getString("OMXAudioDev").c_str();
|
|
|
|
|
2017-06-01 20:08:44 +00:00
|
|
|
//const char* argv[] = args;
|
2017-01-25 15:00:56 +00:00
|
|
|
const char* env[] = { "LD_LIBRARY_PATH=/opt/vc/libs:/usr/lib/omxplayer", NULL };
|
2017-03-25 17:02:28 +00:00
|
|
|
|
2017-01-25 15:00:56 +00:00
|
|
|
// Redirect stdout
|
|
|
|
int fdin = open("/dev/null", O_RDONLY);
|
|
|
|
int fdout = open("/dev/null", O_WRONLY);
|
|
|
|
dup2(fdin, 0);
|
|
|
|
dup2(fdout, 1);
|
|
|
|
// Run the omxplayer binary
|
|
|
|
execve("/usr/bin/omxplayer.bin", (char**)argv, (char**)env);
|
2017-03-25 17:02:28 +00:00
|
|
|
|
2017-01-25 15:00:56 +00:00
|
|
|
_exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-25 17:02:28 +00:00
|
|
|
void catch_child(int sig_num)
|
|
|
|
{
|
|
|
|
/* when we get here, we know there's a zombie child waiting */
|
|
|
|
int child_status;
|
|
|
|
wait(&child_status);
|
|
|
|
}
|
|
|
|
|
2017-01-25 15:00:56 +00:00
|
|
|
void VideoPlayerComponent::stopVideo()
|
|
|
|
{
|
|
|
|
mIsPlaying = false;
|
|
|
|
mStartDelayed = false;
|
|
|
|
|
|
|
|
// Stop the player process
|
|
|
|
if (mPlayerPid != -1)
|
|
|
|
{
|
|
|
|
int status;
|
|
|
|
kill(mPlayerPid, SIGKILL);
|
|
|
|
waitpid(mPlayerPid, &status, WNOHANG);
|
|
|
|
mPlayerPid = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|