libeplayer3: implement multi-program support

Origin commit data
------------------
Branch: master
Commit: 9112c4d16d
Author: martii <m4rtii@gmx.de>
Date: 2014-08-22 (Fri, 22 Aug 2014)


------------------
No further description and justification available within origin commit message!

------------------
This commit was generated by Migit
This commit is contained in:
martii
2014-08-22 18:53:52 +02:00
parent 1f9ba06b01
commit b52c242437
14 changed files with 320 additions and 74 deletions

View File

@@ -44,6 +44,7 @@ class Track;
class Input
{
friend class Player;
friend class WriterPCM; // needs calcPts()
friend int interrupt_cb(void *arg);
private:

View File

@@ -46,10 +46,18 @@ struct Track
int pid;
AVStream *stream;
bool inactive;
bool hidden; // not part of currently selected program
bool is_static;
int ac3flags;
int type, mag, page; // for teletext
Track() : pid(-1), stream(NULL), inactive(0), is_static(0), ac3flags(0) {}
Track() : pid(-1), stream(NULL), inactive(false), hidden(false), is_static(false), ac3flags(0) {}
};
struct Program
{
int id;
std::string title;
std::vector<AVStream *> streams;
};
class Manager
@@ -60,6 +68,7 @@ class Manager
Player *player;
OpenThreads::Mutex mutex;
std::map<int,Track*> videoTracks, audioTracks, subtitleTracks, teletextTracks;
std::map<int,Program> Programs;
void addTrack(std::map<int,Track*> &tracks, Track &track);
Track *getTrack(std::map<int,Track*> &tracks, int pid);
std::vector<Track> getTracks(std::map<int,Track*> &tracks);
@@ -68,11 +77,14 @@ class Manager
void addAudioTrack(Track &track);
void addSubtitleTrack(Track &track);
void addTeletextTrack(Track &track);
void addProgram(Program &program);
std::vector<Track> getVideoTracks();
std::vector<Track> getAudioTracks();
std::vector<Track> getSubtitleTracks();
std::vector<Track> getTeletextTracks();
std::vector<Program> getPrograms();
bool selectProgram(const int id);
Track *getVideoTrack(int pid);
Track *getAudioTrack(int pid);

View File

@@ -56,6 +56,7 @@ class Player {
friend class Output;
friend class Manager;
friend class cPlayback;
friend class WriterPCM;
friend int interrupt_cb(void *arg);
private:
@@ -117,6 +118,10 @@ class Player {
AVFormatContext *GetAVFormatContext() { return input.GetAVFormatContext(); }
void ReleaseAVFormatContext() { input.ReleaseAVFormatContext(); }
bool GetPrograms(std::vector<std::string> &keys, std::vector<std::string> &values);
bool SelectProgram(int key);
bool SelectProgram(std::string &key);
Player();
};
#endif

View File

@@ -37,10 +37,13 @@ extern "C" {
#define AV_CODEC_ID_INJECTPCM AV_CODEC_ID_PCM_S16LE
class Player;
class Writer
{
protected:
int fd;
Player *player;
public:
static void Register(Writer *w, enum AVCodecID id, video_encoding_t encoding);
static void Register(Writer *w, enum AVCodecID id, audio_encoding_t encoding);
@@ -48,7 +51,7 @@ class Writer
static audio_encoding_t GetAudioEncoding(enum AVCodecID id);
static Writer *GetWriter(enum AVCodecID id, enum AVMediaType codec_type);
virtual void Init(int _fd, AVStream * /*stream*/ ) { fd = _fd; }
virtual void Init(int _fd, AVStream * /*stream*/, Player *_player ) { fd = _fd; player = _player; }
virtual bool Write(AVPacket *packet, int64_t pts);
};
#endif

View File

@@ -20,7 +20,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#define ENABLE_AVLOG 0
#define ENABLE_LOGGING 1
#include <stdio.h>
#include <stdlib.h>
@@ -80,6 +80,32 @@ extern void dvbsub_ass_clear(void);
// from neutrino-mp/lib/lib/libtuxtxt/tuxtxt_common.h
extern void teletext_write(int pid, uint8_t *data, int size);
static std::string lastlog_message;
static unsigned int lastlog_repeats;
static void log_callback(void *ptr __attribute__ ((unused)), int lvl __attribute__ ((unused)), const char *format, va_list ap)
{
char m[1024];
if (sizeof(m) - 1 > (unsigned int) vsnprintf(m, sizeof(m), format, ap)) {
if (lastlog_message.compare(m) || lastlog_repeats > 999) {
if (lastlog_repeats)
fprintf(stderr, "last message repeated %u times\n", lastlog_repeats);
lastlog_message = m;
lastlog_repeats = 0;
fprintf(stderr, "%s", m);
} else
lastlog_repeats++;
}
}
static void logprintf(const char *format, ...)
{
va_list ap;
va_start(ap, format);
log_callback(NULL, 0, format, ap);
va_end(ap);
}
bool Input::Play()
{
hasPlayThreadStarted = 1;
@@ -87,11 +113,9 @@ bool Input::Play()
int64_t showtime = 0;
bool restart_audio_resampling = false;
bool bof = false;
int warnAudioWrite = 0;
int warnVideoWrite = 0;
// HACK: Drop all video frames until the first audio frame was seen to keep player2 from stuttering.
// This seems to be necessary for network streaming only ...
// HACK: Dropping all video frames until the first audio frame was seen will keep player2 from stuttering.
// Oddly, this seems to be necessary for network streaming only ...
bool audioSeen = !audioTrack || !player->isHttp;
while (player->isPlaying && !player->abortRequested) {
@@ -184,14 +208,8 @@ bool Input::Play()
if (_videoTrack && (_videoTrack->stream == stream)) {
int64_t pts = calcPts(stream, packet.pts);
if (audioSeen && !player->output.Write(stream, &packet, pts)) {
if (warnVideoWrite)
warnVideoWrite--;
else {
fprintf(stderr, "writing data to %s device failed\n", "video");
warnVideoWrite = 100;
}
}
if (audioSeen && !player->output.Write(stream, &packet, pts))
logprintf("writing data to %s device failed\n", "video");
} else if (_audioTrack && (_audioTrack->stream == stream)) {
if (restart_audio_resampling) {
restart_audio_resampling = false;
@@ -199,14 +217,8 @@ bool Input::Play()
}
if (!player->isBackWard) {
int64_t pts = calcPts(stream, packet.pts);
if (!player->output.Write(stream, &packet, _videoTrack ? pts : 0)) {
if (warnAudioWrite)
warnAudioWrite--;
else {
fprintf(stderr, "writing data to %s device failed\n", "audio");
warnAudioWrite = 100;
}
}
if (!player->output.Write(stream, &packet, _videoTrack ? pts : 0))
logprintf("writing data to %s device failed\n", "audio");
}
audioSeen = true;
} else if (_subtitleTrack && (_subtitleTrack->stream == stream)) {
@@ -241,7 +253,7 @@ bool Input::Play()
}
av_free_packet(&packet);
} /* while */
} /* while */
if (player->abortRequested)
player->output.Clear();
@@ -264,25 +276,26 @@ bool Input::Play()
return res;
}
#if ENABLE_AVLOG
static std::string lastlog_message;
static unsigned int lastlog_repeats;
static void log_callback(void *ptr __attribute__ ((unused)), int lvl __attribute__ ((unused)), const char *format, va_list ap)
static int lock_callback(void **mutex, enum AVLockOp op)
{
char m[1024];
if (sizeof(m) - 1 > (unsigned int) vsnprintf(m, sizeof(m), format, ap)) {
if (lastlog_message.compare(m) || lastlog_repeats > 999) {
if (lastlog_repeats)
fprintf(stderr, "last message repeated %u times\n", lastlog_repeats);
lastlog_message = m;
lastlog_repeats = 0;
fprintf(stderr, "%s", m);
} else
lastlog_repeats++;
switch (op) {
case AV_LOCK_CREATE:
*mutex = (void *) new OpenThreads::Mutex;
return !*mutex;
case AV_LOCK_DESTROY:
delete static_cast<OpenThreads::Mutex *>(*mutex);
*mutex = NULL;
return 0;
case AV_LOCK_OBTAIN:
static_cast<OpenThreads::Mutex *>(*mutex)->lock();
return 0;
case AV_LOCK_RELEASE:
static_cast<OpenThreads::Mutex *>(*mutex)->unlock();
return 0;
default:
return -1;
}
}
#endif
bool Input::ReadSubtitle(const char *filename, const char *format, int pid)
{
@@ -360,7 +373,8 @@ bool Input::ReadSubtitles(const char *filename) {
bool Input::Init(const char *filename)
{
abortPlayback = false;
#if ENABLE_AVLOG
av_lockmgr_register(lock_callback);
#if ENABLE_LOGGING
av_log_set_callback(log_callback);
#endif
@@ -451,6 +465,7 @@ bool Input::UpdateTracks()
av_dump_format(avfc, 0, player->url.c_str(), 0);
bool use_index_as_pid = false;
for (unsigned int n = 0; n < avfc->nb_streams; n++) {
AVStream *stream = avfc->streams[n];
@@ -458,18 +473,27 @@ bool Input::UpdateTracks()
track.stream = stream;
AVDictionaryEntry *lang = av_dict_get(stream->metadata, "language", NULL, 0);
track.title = lang ? lang->value : "";
track.pid = stream->id;
if (!track.pid)
track.pid = n + 1;
if (!use_index_as_pid)
switch (stream->codec->codec_type) {
case AVMEDIA_TYPE_VIDEO:
case AVMEDIA_TYPE_AUDIO:
case AVMEDIA_TYPE_SUBTITLE:
if (!stream->id)
use_index_as_pid = true;
default:
break;
}
track.pid = use_index_as_pid ? n + 1: stream->id;
switch (stream->codec->codec_type) {
case AVMEDIA_TYPE_VIDEO: {
case AVMEDIA_TYPE_VIDEO:
player->manager.addVideoTrack(track);
if (!videoTrack)
videoTrack = player->manager.getVideoTrack(track.pid);
break;
}
case AVMEDIA_TYPE_AUDIO: {
case AVMEDIA_TYPE_AUDIO:
switch(stream->codec->codec_id) {
case AV_CODEC_ID_MP2:
track.ac3flags = 9;
@@ -496,8 +520,7 @@ bool Input::UpdateTracks()
if (!audioTrack)
audioTrack = player->manager.getAudioTrack(track.pid);
break;
}
case AVMEDIA_TYPE_SUBTITLE: {
case AVMEDIA_TYPE_SUBTITLE:
if (stream->codec->codec_id == AV_CODEC_ID_DVB_TELETEXT) {
std::string l = lang ? lang->value : "";
uint8_t *data = stream->codec->extradata;
@@ -525,13 +548,25 @@ bool Input::UpdateTracks()
player->manager.addSubtitleTrack(track);
}
break;
}
default:
fprintf(stderr, "not handled or unknown codec_type %d\n", stream->codec->codec_type);
break;
}
}
for (unsigned int n = 0; n < avfc->nb_programs; n++) {
AVProgram *p = avfc->programs[n];
if (p->nb_stream_indexes) {
AVDictionaryEntry *name = av_dict_get(p->metadata, "name", NULL, 0);
Program program;
program.title = name ? name->value : "";
program.id = p->id;
for (unsigned m = 0; m < p->nb_stream_indexes; m++)
program.streams.push_back(avfc->streams[p->stream_index[m]]);
player->manager.addProgram(program);
}
}
return true;
}

View File

@@ -61,7 +61,7 @@ std::vector<Track> Manager::getTracks(std::map<int,Track*> &tracks)
std::vector<Track> res;
OpenThreads::ScopedLock<OpenThreads::Mutex> m_lock(mutex);
for(std::map<int,Track*>::iterator it = tracks.begin(); it != tracks.end(); ++it)
if (!it->second->inactive)
if (!it->second->inactive && !it->second->hidden)
res.push_back(*it->second);
return res;
}
@@ -133,6 +133,107 @@ bool Manager::initTrackUpdate()
return true;
}
void Manager::addProgram(Program &program)
{
Programs[program.id] = program;
}
std::vector<Program> Manager::getPrograms(void)
{
OpenThreads::ScopedLock<OpenThreads::Mutex> m_lock(mutex);
std::vector<Program> res;
for (std::map<int,Program>::iterator it = Programs.begin(); it != Programs.end(); ++it)
res.push_back(it->second);
return res;
}
bool Manager::selectProgram(const int id)
{
OpenThreads::ScopedLock<OpenThreads::Mutex> m_lock(mutex);
std::map<int,Program>::iterator i = Programs.find(id);
if (i != Programs.end()) {
// mark all tracks as hidden
for (std::map<int,Track*>::iterator it = audioTracks.begin(); it != audioTracks.end(); ++it)
it->second->hidden = true;
for (std::map<int, Track*>::iterator it = videoTracks.begin(); it != videoTracks.end(); ++it)
it->second->hidden = true;
for (std::map<int,Track*>::iterator it = subtitleTracks.begin(); it != subtitleTracks.end(); ++it)
it->second->hidden = true;
for (std::map<int,Track*>::iterator it = teletextTracks.begin(); it != teletextTracks.end(); ++it)
it->second->hidden = true;
// unhide tracks that are part of the selected program
for (unsigned int j = 0; j < i->second.streams.size(); j++) {
AVStream *stream = i->second.streams[j];
bool h = true;
for (std::map<int,Track*>::iterator it = audioTracks.begin(); h && (it != audioTracks.end()); ++it)
if (stream == it->second->stream)
h = it->second->hidden = false;
if (!h)
continue;
for (std::map<int, Track*>::iterator it = videoTracks.begin(); h && (it != videoTracks.end()); ++it)
if (stream == it->second->stream)
h = it->second->hidden = false;
if (!h)
continue;
for (std::map<int,Track*>::iterator it = subtitleTracks.begin(); h && (it != subtitleTracks.end()); ++it)
if (stream == it->second->stream)
h = it->second->hidden = false;
if (!h)
continue;
for (std::map<int,Track*>::iterator it = teletextTracks.begin(); h && (it != teletextTracks.end()); ++it)
if (stream == it->second->stream)
h = it->second->hidden = false;
}
// tell ffmpeg what we're interested in
for (std::map<int,Track*>::iterator it = audioTracks.begin(); it != audioTracks.end(); ++it)
if (it->second->hidden || it->second->inactive) {
it->second->stream->discard = AVDISCARD_ALL;
} else {
it->second->stream->discard = AVDISCARD_DEFAULT;
player->input.SwitchAudio(it->second);
}
for (std::map<int, Track*>::iterator it = videoTracks.begin(); it != videoTracks.end(); ++it)
if (it->second->hidden || it->second->inactive) {
it->second->stream->discard = AVDISCARD_ALL;
} else {
it->second->stream->discard = AVDISCARD_DEFAULT;
player->input.SwitchVideo(it->second);
}
for (std::map<int,Track*>::iterator it = subtitleTracks.begin(); it != subtitleTracks.end(); ++it)
if (it->second->hidden || it->second->inactive) {
it->second->stream->discard = AVDISCARD_ALL;
} else {
it->second->stream->discard = AVDISCARD_DEFAULT;
player->input.SwitchSubtitle(it->second);
}
for (std::map<int,Track*>::iterator it = teletextTracks.begin(); it != teletextTracks.end(); ++it)
if (it->second->hidden || it->second->inactive) {
it->second->stream->discard = AVDISCARD_ALL;
} else {
it->second->stream->discard = AVDISCARD_DEFAULT;
player->input.SwitchTeletext(it->second);
}
return true;
}
return false;
}
void Manager::clearTracks()
{
OpenThreads::ScopedLock<OpenThreads::Mutex> m_lock(mutex);
@@ -152,6 +253,8 @@ void Manager::clearTracks()
for (std::map<int,Track*>::iterator it = teletextTracks.begin(); it != teletextTracks.end(); ++it)
delete it->second;
teletextTracks.clear();
Programs.clear();
}
Manager::~Manager()

View File

@@ -129,7 +129,7 @@ bool Output::Play()
if (videoStream && videofd > -1 && (avcc = videoStream->codec)) {
videoWriter = Writer::GetWriter(avcc->codec_id, avcc->codec_type);
videoWriter->Init(videofd, videoStream);
videoWriter->Init(videofd, videoStream, player);
if (dioctl(videofd, VIDEO_SET_ENCODING, videoWriter->GetVideoEncoding(avcc->codec_id))
|| dioctl(videofd, VIDEO_PLAY, NULL))
ret = false;
@@ -137,7 +137,7 @@ bool Output::Play()
if (audioStream && audiofd > -1 && (avcc = audioStream->codec)) {
audioWriter = Writer::GetWriter(avcc->codec_id, avcc->codec_type);
audioWriter->Init(audiofd, audioStream);
audioWriter->Init(audiofd, audioStream, player);
if (dioctl(audiofd, AUDIO_SET_ENCODING, audioWriter->GetAudioEncoding(avcc->codec_id))
|| dioctl(audiofd, AUDIO_PLAY, NULL))
ret = false;
@@ -310,7 +310,7 @@ bool Output::SwitchAudio(AVStream *stream)
if (!avcc)
return false;
audioWriter = Writer::GetWriter(avcc->codec_id, avcc->codec_type);
audioWriter->Init(audiofd, audioStream);
audioWriter->Init(audiofd, audioStream, player);
if (audiofd > -1) {
dioctl(audiofd, AUDIO_SET_ENCODING, Writer::GetAudioEncoding(avcc->codec_id));
dioctl(audiofd, AUDIO_PLAY, NULL);
@@ -334,7 +334,7 @@ bool Output::SwitchVideo(AVStream *stream)
if (!avcc)
return false;
videoWriter = Writer::GetWriter(avcc->codec_id, avcc->codec_type);
videoWriter->Init(videofd, videoStream);
videoWriter->Init(videofd, videoStream, player);
if (videofd > -1) {
dioctl(videofd, VIDEO_SET_ENCODING, Writer::GetVideoEncoding(avcc->codec_id));
dioctl(videofd, VIDEO_PLAY, NULL);

View File

@@ -25,6 +25,7 @@
#include <sys/types.h>
#include <pthread.h>
#include <sys/prctl.h>
#include <sstream>
#include "player.h"
#include "misc.h"
@@ -411,3 +412,33 @@ int Player::GetTeletextPid()
Track *track = input.teletextTrack;
return track ? track->pid : 0;
}
bool Player::GetPrograms(std::vector<std::string> &keys, std::vector<std::string> &values)
{
keys.clear();
values.clear();
std::vector<Program> p = manager.getPrograms();
if (p.empty())
return false;
for (std::vector<Program>::iterator it = p.begin(); it != p.end(); ++it) {
std::stringstream s;
s << it->id;
keys.push_back(s.str());
values.push_back(it->title);
}
return true;
}
bool Player::SelectProgram(int key)
{
return manager.selectProgram(key);
}
bool Player::SelectProgram(std::string &key)
{
return manager.selectProgram(atoi(key.c_str()));
}

View File

@@ -40,14 +40,15 @@ class WriterDIVX : public Writer
AVStream *stream;
public:
bool Write(AVPacket *packet, int64_t pts);
void Init(int fd, AVStream *_stream);
void Init(int fd, AVStream *_stream, Player *player);
WriterDIVX();
};
void WriterDIVX::Init(int _fd, AVStream *_stream)
void WriterDIVX::Init(int _fd, AVStream *_stream, Player *_player)
{
fd = _fd;
stream = _stream;
player = _player;
initialHeader = true;
}

View File

@@ -32,6 +32,7 @@
#include "misc.h"
#include "pes.h"
#include "writer.h"
#include "player.h"
extern "C" {
#include <libavutil/avutil.h>
@@ -84,7 +85,7 @@ class WriterPCM : public Writer
bool Write(AVPacket *packet, int64_t pts);
bool prepareClipPlay();
bool writePCM(int64_t Pts, uint8_t *data, unsigned int size);
void Init(int _fd, AVStream *_stream);
void Init(int _fd, AVStream *_stream, Player *_player);
WriterPCM();
};
@@ -219,10 +220,11 @@ bool WriterPCM::writePCM(int64_t Pts, uint8_t *data, unsigned int size)
return res;
}
void WriterPCM::Init(int _fd, AVStream *_stream)
void WriterPCM::Init(int _fd, AVStream *_stream, Player *_player)
{
fd = _fd;
stream = _stream;
player = _player;
initialHeader = true;
restart_audio_resampling = true;
}
@@ -320,6 +322,8 @@ bool WriterPCM::Write(AVPacket *packet, int64_t pts)
continue;
}
pts = player->input.calcPts(stream, av_frame_get_best_effort_timestamp(decoded_frame));
int in_samples = decoded_frame->nb_samples;
int out_samples = av_rescale_rnd(swr_get_delay(swr, c->sample_rate) + in_samples, out_sample_rate, c->sample_rate, AV_ROUND_UP);
if (out_samples > out_samples_max) {
@@ -339,8 +343,6 @@ bool WriterPCM::Write(AVPacket *packet, int64_t pts)
restart_audio_resampling = true;
break;
}
pts = 0;
}
return !packet_size;
}

View File

@@ -51,14 +51,15 @@ class WriterVC1 : public Writer
AVStream *stream;
public:
bool Write(AVPacket *packet, int64_t pts);
void Init(int _fd, AVStream *_stream);
void Init(int _fd, AVStream *_stream, Player *_player);
WriterVC1();
};
void WriterVC1::Init(int _fd, AVStream *_stream)
void WriterVC1::Init(int _fd, AVStream *_stream, Player *_player)
{
fd = _fd;
stream = _stream;
player = _player;
initialHeader = true;
}

View File

@@ -58,14 +58,15 @@ class WriterWMV : public Writer
AVStream *stream;
public:
bool Write(AVPacket *packet, int64_t pts);
void Init(int _fd, AVStream *_stream);
void Init(int _fd, AVStream *_stream, Player *_player);
WriterWMV();
};
void WriterWMV::Init(int _fd, AVStream *_stream)
void WriterWMV::Init(int _fd, AVStream *_stream, Player *_player)
{
fd = _fd;
stream = _stream;
player = _player;
initialHeader = true;
}

View File

@@ -80,10 +80,27 @@ bool cPlayback::Start(char *filename, int vpid, int vtype, int apid, int ac3, in
videoDecoder->Stop(false);
audioDecoder->Stop();
} else {
std::vector<std::string> keys, values;
int selected_program = 0;
if (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());
if (!keys.size() || !player->SelectProgram(selected_program)) {
if (apid)
SetAPid(apid);
if (vpid)
SetVPid(vpid);
}
playing = true;
player->output.Open();
if (apid)
SetAPid(apid, 0);
ret = player->Play();
if (ret && !isHTTP)
playing = ret = player->Pause();
@@ -109,6 +126,11 @@ bool cPlayback::SetAPid(int pid, bool /* ac3 */)
return player->SwitchAudio(pid);
}
bool cPlayback::SetVPid(int pid)
{
return player->SwitchVideo(pid);
}
bool cPlayback::SetSubtitlePid(int pid)
{
return player->SwitchSubtitle(pid);
@@ -321,6 +343,9 @@ cPlayback::cPlayback(int num __attribute__((unused)))
{
playing = false;
decoders_closed = false;
ProgramSelectionCallback = NULL;
ProgramSelectionCallbackData = NULL;
player = new Player();
}
@@ -368,6 +393,24 @@ AVFormatContext *cPlayback::GetAVFormatContext()
return player ? player->GetAVFormatContext() : NULL;
}
void cPlayback::ReleaseAVFormatContext() { if (player)
player->ReleaseAVFormatContext();
void cPlayback::ReleaseAVFormatContext()
{
if (player)
player->ReleaseAVFormatContext();
}
bool cPlayback::GetPrograms(std::vector<std::string> &keys, std::vector<std::string> &values)
{
return player->GetPrograms(keys, values);
}
bool cPlayback::SelectProgram(std::string &key)
{
return player->SelectProgram(key);
}
void cPlayback::SetProgramSelectionCallback(const char *(*fun)(void *, std::vector<std::string> &keys, std::vector<std::string> &values), void *opaque)
{
ProgramSelectionCallback = fun;
ProgramSelectionCallbackData = opaque;
}

View File

@@ -29,6 +29,11 @@ class cPlayback
off_t last_size;
int init_jump;
Player *player;
const char *(*ProgramSelectionCallback)(void *, std::vector<std::string> &keys, std::vector<std::string> &values);
void *ProgramSelectionCallbackData;
bool GetPrograms(std::vector<std::string> &keys, std::vector<std::string> &values);
bool SelectProgram(std::string &key);
public:
cPlayback(int num = 0);
~cPlayback();
@@ -36,7 +41,8 @@ class cPlayback
bool Open(playmode_t PlayMode);
void Close(void);
bool Start(char *filename, int vpid, int vtype, int apid, int ac3, int duration);
bool SetAPid(int pid, bool ac3);
bool SetAPid(int pid, bool ac3 = false);
bool SetVPid(int pid);
bool SetSubtitlePid(int pid);
bool SetTeletextPid(int pid);
int GetAPid(void);
@@ -55,16 +61,18 @@ class cPlayback
void RequestAbort(void);
bool IsPlaying(void);
uint64_t GetReadCount(void);
#if 0
void FindAllSubs(uint16_t *pids, unsigned short *supported, uint16_t *numpida, std::string *language);
bool SelectSubtitles(int pid);
#endif
void GetChapters(std::vector<int> &positions, std::vector<std::string> &titles);
void GetMetadata(std::vector<std::string> &keys, std::vector<std::string> &values);
void SetProgramSelectionCallback(const char *(*fun)(void *, std::vector<std::string> &keys, std::vector<std::string> &values), void *opaque);
AVFormatContext *GetAVFormatContext();
void ReleaseAVFormatContext();
#if 0
void FindAllSubs(uint16_t *pids, unsigned short *supported, uint16_t *numpida, std::string *language);
bool SelectSubtitles(int pid);
// Functions that are not used by movieplayer.cpp:
bool GetOffset(off64_t &offset);
bool IsPlaying(void) const;