From 9112c4d16d05cb96a0ccd39c8fde7b2fa9ba23e9 Mon Sep 17 00:00:00 2001 From: martii Date: Fri, 22 Aug 2014 18:53:52 +0200 Subject: [PATCH] libeplayer3: implement multi-program support --- libeplayer3/include/input.h | 1 + libeplayer3/include/manager.h | 14 +++- libeplayer3/include/player.h | 5 ++ libeplayer3/include/writer.h | 5 +- libeplayer3/input.cpp | 131 +++++++++++++++++++----------- libeplayer3/manager.cpp | 105 +++++++++++++++++++++++- libeplayer3/output.cpp | 8 +- libeplayer3/player.cpp | 31 +++++++ libeplayer3/writer/divx.cpp | 5 +- libeplayer3/writer/pcm.cpp | 10 ++- libeplayer3/writer/vc1.cpp | 5 +- libeplayer3/writer/wmv.cpp | 5 +- libspark/playback_libeplayer3.cpp | 51 +++++++++++- libspark/playback_libeplayer3.h | 18 ++-- 14 files changed, 320 insertions(+), 74 deletions(-) diff --git a/libeplayer3/include/input.h b/libeplayer3/include/input.h index 8239019..9f58f92 100644 --- a/libeplayer3/include/input.h +++ b/libeplayer3/include/input.h @@ -44,6 +44,7 @@ class Track; class Input { friend class Player; + friend class WriterPCM; // needs calcPts() friend int interrupt_cb(void *arg); private: diff --git a/libeplayer3/include/manager.h b/libeplayer3/include/manager.h index 8c30568..364595b 100644 --- a/libeplayer3/include/manager.h +++ b/libeplayer3/include/manager.h @@ -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 streams; }; class Manager @@ -60,6 +68,7 @@ class Manager Player *player; OpenThreads::Mutex mutex; std::map videoTracks, audioTracks, subtitleTracks, teletextTracks; + std::map Programs; void addTrack(std::map &tracks, Track &track); Track *getTrack(std::map &tracks, int pid); std::vector getTracks(std::map &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 getVideoTracks(); std::vector getAudioTracks(); std::vector getSubtitleTracks(); std::vector getTeletextTracks(); + std::vector getPrograms(); + bool selectProgram(const int id); Track *getVideoTrack(int pid); Track *getAudioTrack(int pid); diff --git a/libeplayer3/include/player.h b/libeplayer3/include/player.h index 0b53047..9926d1e 100644 --- a/libeplayer3/include/player.h +++ b/libeplayer3/include/player.h @@ -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 &keys, std::vector &values); + bool SelectProgram(int key); + bool SelectProgram(std::string &key); + Player(); }; #endif diff --git a/libeplayer3/include/writer.h b/libeplayer3/include/writer.h index bd699ff..4d6ee2e 100644 --- a/libeplayer3/include/writer.h +++ b/libeplayer3/include/writer.h @@ -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 diff --git a/libeplayer3/input.cpp b/libeplayer3/input.cpp index 5fc48a5..52085a0 100644 --- a/libeplayer3/input.cpp +++ b/libeplayer3/input.cpp @@ -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 #include @@ -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(*mutex); + *mutex = NULL; + return 0; + case AV_LOCK_OBTAIN: + static_cast(*mutex)->lock(); + return 0; + case AV_LOCK_RELEASE: + static_cast(*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; } diff --git a/libeplayer3/manager.cpp b/libeplayer3/manager.cpp index bb163a4..9dc1d38 100644 --- a/libeplayer3/manager.cpp +++ b/libeplayer3/manager.cpp @@ -61,7 +61,7 @@ std::vector Manager::getTracks(std::map &tracks) std::vector res; OpenThreads::ScopedLock m_lock(mutex); for(std::map::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 Manager::getPrograms(void) +{ + OpenThreads::ScopedLock m_lock(mutex); + std::vector res; + for (std::map::iterator it = Programs.begin(); it != Programs.end(); ++it) + res.push_back(it->second); + return res; +} + +bool Manager::selectProgram(const int id) +{ + OpenThreads::ScopedLock m_lock(mutex); + std::map::iterator i = Programs.find(id); + if (i != Programs.end()) { + + // mark all tracks as hidden + for (std::map::iterator it = audioTracks.begin(); it != audioTracks.end(); ++it) + it->second->hidden = true; + + for (std::map::iterator it = videoTracks.begin(); it != videoTracks.end(); ++it) + it->second->hidden = true; + + for (std::map::iterator it = subtitleTracks.begin(); it != subtitleTracks.end(); ++it) + it->second->hidden = true; + + for (std::map::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::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::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::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::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::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::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::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::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 m_lock(mutex); @@ -152,6 +253,8 @@ void Manager::clearTracks() for (std::map::iterator it = teletextTracks.begin(); it != teletextTracks.end(); ++it) delete it->second; teletextTracks.clear(); + + Programs.clear(); } Manager::~Manager() diff --git a/libeplayer3/output.cpp b/libeplayer3/output.cpp index e812afa..6855824 100644 --- a/libeplayer3/output.cpp +++ b/libeplayer3/output.cpp @@ -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); diff --git a/libeplayer3/player.cpp b/libeplayer3/player.cpp index 0dab1c4..21d3bad 100644 --- a/libeplayer3/player.cpp +++ b/libeplayer3/player.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #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 &keys, std::vector &values) +{ + keys.clear(); + values.clear(); + + std::vector p = manager.getPrograms(); + + if (p.empty()) + return false; + + for (std::vector::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())); +} diff --git a/libeplayer3/writer/divx.cpp b/libeplayer3/writer/divx.cpp index 185665c..2138dc1 100644 --- a/libeplayer3/writer/divx.cpp +++ b/libeplayer3/writer/divx.cpp @@ -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; } diff --git a/libeplayer3/writer/pcm.cpp b/libeplayer3/writer/pcm.cpp index 413b7d6..cb84f27 100644 --- a/libeplayer3/writer/pcm.cpp +++ b/libeplayer3/writer/pcm.cpp @@ -32,6 +32,7 @@ #include "misc.h" #include "pes.h" #include "writer.h" +#include "player.h" extern "C" { #include @@ -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; } diff --git a/libeplayer3/writer/vc1.cpp b/libeplayer3/writer/vc1.cpp index 94d845d..34ef182 100644 --- a/libeplayer3/writer/vc1.cpp +++ b/libeplayer3/writer/vc1.cpp @@ -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; } diff --git a/libeplayer3/writer/wmv.cpp b/libeplayer3/writer/wmv.cpp index c20a0d6..ecc516e 100644 --- a/libeplayer3/writer/wmv.cpp +++ b/libeplayer3/writer/wmv.cpp @@ -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; } diff --git a/libspark/playback_libeplayer3.cpp b/libspark/playback_libeplayer3.cpp index bace4d1..303030e 100644 --- a/libspark/playback_libeplayer3.cpp +++ b/libspark/playback_libeplayer3.cpp @@ -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 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 &keys, std::vector &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 &keys, std::vector &values), void *opaque) +{ + ProgramSelectionCallback = fun; + ProgramSelectionCallbackData = opaque; } diff --git a/libspark/playback_libeplayer3.h b/libspark/playback_libeplayer3.h index ca032e9..0608911 100644 --- a/libspark/playback_libeplayer3.h +++ b/libspark/playback_libeplayer3.h @@ -29,6 +29,11 @@ class cPlayback off_t last_size; int init_jump; Player *player; + const char *(*ProgramSelectionCallback)(void *, std::vector &keys, std::vector &values); + void *ProgramSelectionCallbackData; + + bool GetPrograms(std::vector &keys, std::vector &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 &positions, std::vector &titles); void GetMetadata(std::vector &keys, std::vector &values); + void SetProgramSelectionCallback(const char *(*fun)(void *, std::vector &keys, std::vector &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;