Files
libstb-hal/libspark/playback_libeplayer3.cpp
Stefan Seyfried fd2f0f1fd4 cPlayback: implement new libcoolstream interfaces
a new "Start" and changed "SelectSubtitles" function are
implemented to fix compilation (mostly stubbed out, though)
2016-10-22 11:29:32 +02:00

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 &current)
{
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