mirror of
https://github.com/tuxbox-neutrino/libstb-hal.git
synced 2025-08-26 15:02:58 +02:00
a new "Start" and changed "SelectSubtitles" function are implemented to fix compilation (mostly stubbed out, though)
519 lines
11 KiB
C++
519 lines
11 KiB
C++
/*
|
|
* CPlayback implementation for SH4 using libeplayer3
|
|
*
|
|
* (C) 2010-2015 Stefan Seyfried
|
|
*
|
|
* original code is from tdt git:
|
|
* git://gitorious.org/open-duckbox-project-sh4/tdt.git
|
|
*
|
|
* lots of changes and huge improvements are
|
|
* (C) 2013,2014 'martii' <m4rtii@gmx.de>
|
|
*
|
|
* License: GPLv2 or later, as the rest of libstb-hal
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
|
|
#include <audio_priv.h>
|
|
#include <video_priv.h>
|
|
|
|
#include "player.h"
|
|
//#include "playback_libeplayer3.h"
|
|
#include "playback_hal.h"
|
|
#include "lt_debug.h"
|
|
|
|
#define lt_debug(args...) _lt_debug(HAL_DEBUG_PLAYBACK, this, args)
|
|
#define lt_info(args...) _lt_info(HAL_DEBUG_PLAYBACK, this, args)
|
|
|
|
|
|
extern ADec *adec;
|
|
extern cVideo *videoDecoder;
|
|
static bool decoders_closed = false;
|
|
|
|
static playmode_t pm;
|
|
static std::string fn_ts;
|
|
static std::string fn_xml;
|
|
static off_t last_size;
|
|
static int init_jump;
|
|
|
|
class PBPrivate
|
|
{
|
|
public:
|
|
bool enabled;
|
|
bool playing;
|
|
int speed;
|
|
int astream;
|
|
bool eof;
|
|
int length;
|
|
std::string curfile;
|
|
Player *player;
|
|
PBPrivate() {
|
|
enabled = false;
|
|
playing = false;
|
|
speed = 0;
|
|
astream = -1;
|
|
eof = false;
|
|
length = 0;
|
|
curfile = "";
|
|
player = new Player;
|
|
};
|
|
~PBPrivate() {
|
|
delete player;
|
|
};
|
|
};
|
|
|
|
bool cPlayback::Open(playmode_t PlayMode)
|
|
{
|
|
const char *aPLAYMODE[] = {
|
|
"PLAYMODE_TS",
|
|
"PLAYMODE_FILE"
|
|
};
|
|
|
|
if (PlayMode != PLAYMODE_TS)
|
|
{
|
|
adec->closeDevice();
|
|
videoDecoder->vdec->closeDevice();
|
|
decoders_closed = true;
|
|
}
|
|
|
|
lt_info("%s - PlayMode=%s\n", __func__, aPLAYMODE[PlayMode]);
|
|
pm = PlayMode;
|
|
fn_ts = "";
|
|
fn_xml = "";
|
|
last_size = 0;
|
|
pd->speed = 0;
|
|
init_jump = -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void cPlayback::Close(void)
|
|
{
|
|
lt_info("%s\n", __func__);
|
|
|
|
//Dagobert: movieplayer does not call stop, it calls close ;)
|
|
Stop();
|
|
if (decoders_closed)
|
|
{
|
|
adec->openDevice();
|
|
videoDecoder->vdec->openDevice();
|
|
decoders_closed = false;
|
|
}
|
|
}
|
|
|
|
/* TODO: implement cookie stuff */
|
|
bool cPlayback::Start(std::string filename, std::string /*headers*/)
|
|
{
|
|
return Start((char *)filename.c_str(), 0, 0, 0, 0, 0);
|
|
}
|
|
|
|
bool cPlayback::Start(char *filename, unsigned short vpid, int vtype, unsigned short apid, int ac3, unsigned int)
|
|
{
|
|
bool ret = false;
|
|
bool isHTTP = false;
|
|
bool no_probe = false;
|
|
|
|
lt_info("%s - filename=%s vpid=%u vtype=%d apid=%u ac3=%d\n",
|
|
__func__, filename, vpid, vtype, apid, ac3);
|
|
|
|
Player *player = pd->player;
|
|
init_jump = -1;
|
|
|
|
std::string file;
|
|
if (*filename == '/')
|
|
file = "file://";
|
|
file += filename;
|
|
pd->curfile = file;
|
|
|
|
if (file.substr(0, 7) == "file://") {
|
|
if (file.substr(file.length() - 3) == ".ts") {
|
|
fn_ts = file.substr(7);
|
|
fn_xml = file.substr(7, file.length() - 9);
|
|
fn_xml += "xml";
|
|
no_probe = true;
|
|
}
|
|
} else
|
|
isHTTP = true;
|
|
|
|
if (player->Open(file.c_str(), no_probe)) {
|
|
if (pm == PLAYMODE_TS) {
|
|
struct stat s;
|
|
if (!stat(file.c_str(), &s))
|
|
last_size = s.st_size;
|
|
ret = true;
|
|
videoDecoder->vdec->Stop(false);
|
|
adec->Stop();
|
|
} else {
|
|
std::vector<std::string> keys, values;
|
|
int selected_program = 0;
|
|
if (vpid || apid) {
|
|
;
|
|
#if 0
|
|
} else if (player->GetPrograms(keys, values) && (keys.size() > 1) && ProgramSelectionCallback) {
|
|
const char *key = ProgramSelectionCallback(ProgramSelectionCallbackData, keys, values);
|
|
if (!key) {
|
|
player->Close();
|
|
return false;
|
|
}
|
|
selected_program = atoi(key);
|
|
} else if (keys.size() > 0)
|
|
selected_program = atoi(keys[0].c_str());
|
|
#else
|
|
} else {
|
|
player->GetPrograms(keys, values);
|
|
if (keys.size() > 0) {
|
|
selected_program = atoi(keys[0].c_str());
|
|
int max_br = INT_MAX;
|
|
char *env = getenv("STREAM_MAXBITRATE");
|
|
if (env)
|
|
max_br = atoi(env);
|
|
for (unsigned i = 0; i < keys.size(); i++) {
|
|
lt_info("%s: stream: '%s' value: '%s'\n",
|
|
__func__, keys[i].c_str(), values[i].c_str());
|
|
int bitrate = atoi(values[i].c_str()); /* '1234 kbit/s' */
|
|
if (bitrate <= max_br)
|
|
selected_program = atoi(keys[i].c_str());
|
|
}
|
|
lt_info("%s: selected_program: '%d'\n", __func__, selected_program);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (!keys.size() || !player->SelectProgram(selected_program)) {
|
|
if (apid)
|
|
player->SwitchAudio(apid);
|
|
if (vpid)
|
|
player->SwitchVideo(vpid);
|
|
}
|
|
pd->playing = true;
|
|
player->output.Open();
|
|
ret = player->Play();
|
|
if (ret && !isHTTP)
|
|
pd->playing = ret = player->Pause();
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool cPlayback::Stop(void)
|
|
{
|
|
lt_info("%s playing %d\n", __func__, pd->playing);
|
|
Player *player = pd->player;
|
|
|
|
player->Stop();
|
|
player->output.Close();
|
|
player->Close();
|
|
|
|
pd->playing = false;
|
|
return true;
|
|
}
|
|
|
|
bool cPlayback::SetAPid(unsigned short pid, int /*ac3*/)
|
|
{
|
|
lt_info("%s\n", __func__);
|
|
return pd->player->SwitchAudio(pid);
|
|
}
|
|
|
|
bool cPlayback::SetSpeed(int speed)
|
|
{
|
|
lt_info("%s playing %d speed %d\n", __func__, pd->playing, speed);
|
|
|
|
Player *player = pd->player;
|
|
|
|
if (! decoders_closed)
|
|
{
|
|
adec->closeDevice();
|
|
videoDecoder->vdec->closeDevice();
|
|
decoders_closed = true;
|
|
usleep(500000);
|
|
player->output.Open();
|
|
pd->playing = player->Play();
|
|
}
|
|
|
|
if (!pd->playing)
|
|
return false;
|
|
|
|
bool res = true;
|
|
|
|
pd->speed = speed;
|
|
|
|
if (speed > 1) {
|
|
/* direction switch ? */
|
|
if (player->isBackWard)
|
|
player->FastBackward(0);
|
|
res = player->FastForward(speed);
|
|
} else if (speed < 0) {
|
|
/* direction switch ? */
|
|
if (player->isForwarding)
|
|
player->Continue();
|
|
res = player->FastBackward(speed);
|
|
} else if (speed == 0) {
|
|
/* konfetti: hmmm accessing the member isn't very proper */
|
|
if ((player->isForwarding) || (!player->isBackWard))
|
|
/* res = */ player->Pause();
|
|
else
|
|
/* res = */ player->FastForward(0);
|
|
} else /* speed == 1 */ {
|
|
res = player->Continue();
|
|
}
|
|
|
|
if (init_jump > -1) {
|
|
SetPosition(init_jump);
|
|
init_jump = -1;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
bool cPlayback::GetSpeed(int &speed) const
|
|
{
|
|
lt_debug("%s\n", __func__);
|
|
speed = pd->speed;
|
|
return true;
|
|
}
|
|
|
|
#if 0
|
|
void cPlayback::GetPts(uint64_t &pts)
|
|
{
|
|
pd->player->GetPts((int64_t &) pts);
|
|
}
|
|
#endif
|
|
|
|
// in milliseconds
|
|
bool cPlayback::GetPosition(int &position, int &duration)
|
|
{
|
|
bool got_duration = false;
|
|
lt_debug("%s %d %d\n", __func__, position, duration);
|
|
Player *player = pd->player;
|
|
|
|
/* hack: if the file is growing (timeshift), then determine its length
|
|
* by comparing the mtime with the mtime of the xml file */
|
|
if (pm == PLAYMODE_TS)
|
|
{
|
|
struct stat s;
|
|
if (!stat(fn_ts.c_str(), &s))
|
|
{
|
|
if (!pd->playing || last_size != s.st_size)
|
|
{
|
|
last_size = s.st_size;
|
|
time_t curr_time = s.st_mtime;
|
|
if (!stat(fn_xml.c_str(), &s))
|
|
{
|
|
duration = (curr_time - s.st_mtime) * 1000;
|
|
if (!pd->playing)
|
|
return true;
|
|
got_duration = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!pd->playing)
|
|
return false;
|
|
|
|
if (!player->isPlaying) {
|
|
lt_info("%s !!!!EOF!!!! < -1\n", __func__);
|
|
position = duration;
|
|
pd->eof = true;
|
|
pd->length = duration;
|
|
// duration = 0;
|
|
// this is stupid
|
|
return true;
|
|
}
|
|
|
|
int64_t vpts = 0;
|
|
player->GetPts(vpts);
|
|
|
|
if(vpts <= 0) {
|
|
//printf("ERROR: vpts==0");
|
|
} else {
|
|
/* len is in nanoseconds. we have 90 000 pts per second. */
|
|
position = vpts/90;
|
|
}
|
|
|
|
if (got_duration)
|
|
return true;
|
|
|
|
int64_t length = 0;
|
|
|
|
player->GetDuration(length);
|
|
|
|
if(length <= 0)
|
|
duration = position + 2 * AV_TIME_BASE / 1000;
|
|
else
|
|
duration = length * 1000 / AV_TIME_BASE;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool cPlayback::SetPosition(int position, bool absolute)
|
|
{
|
|
lt_info("%s %d %d\n", __func__, position, absolute);
|
|
if (pd->eof) {
|
|
Close();
|
|
pd->eof = false;
|
|
Start((char *)pd->curfile.c_str(), pd->player->GetVideoPid(), 0, pd->player->GetAudioPid(), 0, 0);
|
|
SetSpeed(pd->speed);
|
|
pd->player->Seek((int64_t)(pd->length - position) * (AV_TIME_BASE / 1000), false);
|
|
return true;
|
|
}
|
|
if (!pd->playing)
|
|
{
|
|
/* the calling sequence is:
|
|
* Start() - paused
|
|
* SetPosition() - which fails if not running
|
|
* SetSpeed() - to start playing
|
|
* so let's remember the initial jump position and later jump to it
|
|
*/
|
|
init_jump = position;
|
|
return false;
|
|
}
|
|
pd->player->Seek((int64_t)position * (AV_TIME_BASE / 1000), absolute);
|
|
return true;
|
|
}
|
|
|
|
void cPlayback::FindAllPids(uint16_t *pids, unsigned short *ac3flags, uint16_t *numpida, std::string *language)
|
|
{
|
|
lt_info("%s\n", __func__);
|
|
unsigned int i = 0;
|
|
|
|
std::vector<Track> tracks = pd->player->manager.getAudioTracks();
|
|
for (std::vector<Track>::iterator it = tracks.begin(); it != tracks.end() && i < MAX_PLAYBACK_PIDS; ++it) {
|
|
pids[i] = it->pid;
|
|
ac3flags[i] = it->ac3flags;
|
|
language[i] = it->title;
|
|
i++;
|
|
}
|
|
*numpida = i;
|
|
}
|
|
|
|
#if 0
|
|
void cPlayback::FindAllSubtitlePids(uint16_t *pids, uint16_t *numpids, std::string *language)
|
|
{
|
|
lt_info("%s\n", __func__);
|
|
unsigned int i = 0;
|
|
|
|
std::vector<Track> tracks = player->manager.getSubtitleTracks();
|
|
for (std::vector<Track>::iterator it = tracks.begin(); it != tracks.end() && i < *numpids; ++it) {
|
|
pids[i] = it->pid;
|
|
language[i] = it->title;
|
|
i++;
|
|
}
|
|
|
|
*numpids = i;
|
|
}
|
|
|
|
void cPlayback::FindAllTeletextsubtitlePids(int *pids, unsigned int *numpids, std::string *language, int *mags, int *pages)
|
|
{
|
|
lt_info("%s\n", __func__);
|
|
unsigned int i = 0;
|
|
|
|
std::vector<Track> tracks = player->manager.getTeletextTracks();
|
|
for (std::vector<Track>::iterator it = tracks.begin(); it != tracks.end() && i < *numpids; ++it) {
|
|
if (it->type != 2 && it->type != 5) // return subtitles only
|
|
continue;
|
|
pids[i] = it->pid;
|
|
language[i] = it->title;
|
|
mags[i] = it->mag;
|
|
pages[i] = it->page;
|
|
i++;
|
|
}
|
|
|
|
*numpids = i;
|
|
}
|
|
|
|
int cPlayback::GetFirstTeletextPid(void)
|
|
{
|
|
std::vector<Track> tracks = player->manager.getTeletextTracks();
|
|
for (std::vector<Track>::iterator it = tracks.begin(); it != tracks.end(); ++it) {
|
|
if (it->type == 1)
|
|
return it->pid;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
unsigned short cPlayback::GetTeletextPid(void)
|
|
{
|
|
lt_info("%s\n", __func__);
|
|
return pd->player->GetTeletextPid();
|
|
}
|
|
#endif
|
|
|
|
/* dummy functions for subtitles */
|
|
void cPlayback::FindAllSubs(uint16_t * /*pids*/, unsigned short * /*supp*/, uint16_t *num, std::string * /*lang*/)
|
|
{
|
|
*num = 0;
|
|
}
|
|
|
|
bool cPlayback::SelectSubtitles(int pid, std::string /*charset*/)
|
|
{
|
|
lt_info("%s pid %d\n", __func__, pid);
|
|
return false;
|
|
}
|
|
|
|
void cPlayback::GetChapters(std::vector<int> &positions, std::vector<std::string> &titles)
|
|
{
|
|
positions.clear();
|
|
titles.clear();
|
|
|
|
pd->player->GetChapters(positions, titles);
|
|
}
|
|
|
|
void cPlayback::GetTitles(std::vector<int> &playlists, std::vector<std::string> &titles, int ¤t)
|
|
{
|
|
playlists.clear();
|
|
titles.clear();
|
|
current = 0;
|
|
}
|
|
|
|
void cPlayback::SetTitle(int /*title*/)
|
|
{
|
|
}
|
|
|
|
void cPlayback::RequestAbort(void)
|
|
{
|
|
}
|
|
|
|
uint64_t cPlayback::GetReadCount(void)
|
|
{
|
|
return pd->player->readCount;
|
|
}
|
|
|
|
//
|
|
cPlayback::cPlayback(int /*num*/)
|
|
{
|
|
lt_info("%s\n", __func__);
|
|
pd = new PBPrivate();
|
|
}
|
|
|
|
cPlayback::~cPlayback()
|
|
{
|
|
lt_info("%s\n", __func__);
|
|
delete pd;
|
|
pd = NULL;
|
|
}
|
|
|
|
#if 0
|
|
bool cPlayback::IsPlaying(void) const
|
|
{
|
|
lt_info("%s\n", __func__);
|
|
|
|
/* konfetti: there is no event/callback mechanism in libeplayer2
|
|
* so in case of ending playback we have no information on a
|
|
* terminated stream currently (or did I oversee it?).
|
|
* So let's ask the player the state.
|
|
*/
|
|
if (playing)
|
|
{
|
|
return player->playback->isPlaying;
|
|
}
|
|
|
|
return playing;
|
|
}
|
|
#endif
|