mirror of
https://github.com/tuxbox-neutrino/libstb-hal.git
synced 2025-08-26 23:13:16 +02:00
libeplayer3: implement Playback and Input classes
This commit is contained in:
@@ -8,8 +8,8 @@ AM_CPPFLAGS += -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS
|
|||||||
AM_CPPFLAGS += -ggdb
|
AM_CPPFLAGS += -ggdb
|
||||||
|
|
||||||
libeplayer3_la_SOURCES = \
|
libeplayer3_la_SOURCES = \
|
||||||
container/container.cpp container/container_ffmpeg.cpp \
|
container/container_ffmpeg.cpp \
|
||||||
manager/manager.cpp output/output.cpp player.cpp \
|
manager/manager.cpp output/output.cpp \
|
||||||
playback/playback.cpp output/writer/writer.cpp output/writer/wmv.cpp \
|
playback/playback.cpp output/writer/writer.cpp output/writer/wmv.cpp \
|
||||||
output/writer/ac3.cpp output/writer/divx.cpp output/writer/pes.cpp \
|
output/writer/ac3.cpp output/writer/divx.cpp output/writer/pes.cpp \
|
||||||
output/writer/dts.cpp output/writer/mpeg2.cpp output/writer/mp3.cpp output/writer/misc.cpp \
|
output/writer/dts.cpp output/writer/mpeg2.cpp output/writer/mp3.cpp output/writer/misc.cpp \
|
||||||
|
@@ -1,71 +0,0 @@
|
|||||||
/*
|
|
||||||
* Main Container Handling.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "player.h"
|
|
||||||
|
|
||||||
#define CONTAINER_DEBUG
|
|
||||||
|
|
||||||
#ifdef CONTAINER_DEBUG
|
|
||||||
|
|
||||||
static short debug_level = 0;
|
|
||||||
|
|
||||||
#define container_printf(level, x...) do { \
|
|
||||||
if (debug_level >= level) printf(x); } while (0)
|
|
||||||
#else
|
|
||||||
#define container_printf(level, x...)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef CONTAINER_SILENT
|
|
||||||
#define container_err(x...) do { printf(x); } while (0)
|
|
||||||
#else
|
|
||||||
#define container_err(x...)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int Command(Player *context, ContainerCmd_t command, const char *argument __attribute__((unused)))
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
container_printf(10, "%s::%s\n", __FILE__, __func__);
|
|
||||||
|
|
||||||
switch (command) {
|
|
||||||
case CONTAINER_ADD:
|
|
||||||
context->container->selectedContainer = &FFMPEGContainer;
|
|
||||||
break;
|
|
||||||
case CONTAINER_DEL:{
|
|
||||||
context->container->selectedContainer = NULL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
container_err("%s::%s ContainerCmd %d not supported!\n", __FILE__,
|
|
||||||
__func__, command);
|
|
||||||
ret = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ContainerHandler_t ContainerHandler = {
|
|
||||||
"Output",
|
|
||||||
NULL,
|
|
||||||
Command
|
|
||||||
};
|
|
File diff suppressed because it is too large
Load Diff
@@ -1,38 +0,0 @@
|
|||||||
#ifndef CONTAINER_H_
|
|
||||||
#define CONTAINER_H_
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
CONTAINER_INIT,
|
|
||||||
CONTAINER_ADD,
|
|
||||||
CONTAINER_PLAY,
|
|
||||||
CONTAINER_STOP,
|
|
||||||
CONTAINER_SEEK,
|
|
||||||
CONTAINER_SEEK_ABS,
|
|
||||||
CONTAINER_LENGTH,
|
|
||||||
CONTAINER_DEL,
|
|
||||||
CONTAINER_SWITCH_AUDIO,
|
|
||||||
CONTAINER_SWITCH_SUBTITLE,
|
|
||||||
CONTAINER_SWITCH_TELETEXT,
|
|
||||||
CONTAINER_METADATA,
|
|
||||||
} ContainerCmd_t;
|
|
||||||
|
|
||||||
struct Player;
|
|
||||||
|
|
||||||
typedef struct Container_s {
|
|
||||||
const char *Name;
|
|
||||||
int (*Command) (Player *, ContainerCmd_t, const char *);
|
|
||||||
const char **Capabilities;
|
|
||||||
} Container_t;
|
|
||||||
|
|
||||||
|
|
||||||
extern Container_t FFMPEGContainer;
|
|
||||||
|
|
||||||
typedef struct ContainerHandler_s {
|
|
||||||
const char *Name;
|
|
||||||
Container_t *selectedContainer;
|
|
||||||
int (*Command) (Player *, ContainerCmd_t, const char *);
|
|
||||||
} ContainerHandler_t;
|
|
||||||
|
|
||||||
#endif
|
|
64
libeplayer3/include/input.h
Normal file
64
libeplayer3/include/input.h
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
#ifndef __INPUT_H__
|
||||||
|
#define __INPUT_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include <OpenThreads/ScopedLock>
|
||||||
|
#include <OpenThreads/Thread>
|
||||||
|
#include <OpenThreads/Condition>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <libavutil/avutil.h>
|
||||||
|
#include <libavutil/time.h>
|
||||||
|
#include <libavformat/avformat.h>
|
||||||
|
#include <libswresample/swresample.h>
|
||||||
|
#include <libavutil/opt.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
class Player;
|
||||||
|
class Track;
|
||||||
|
|
||||||
|
class Input
|
||||||
|
{
|
||||||
|
friend class Player;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Track *videoTrack;
|
||||||
|
Track *audioTrack;
|
||||||
|
Track *subtitleTrack;
|
||||||
|
Track *teletextTrack;
|
||||||
|
|
||||||
|
int hasPlayThreadStarted;
|
||||||
|
float seek_sec_abs;
|
||||||
|
float seek_sec_rel;
|
||||||
|
bool isContainerRunning;
|
||||||
|
bool terminating;
|
||||||
|
|
||||||
|
Player *context;
|
||||||
|
AVFormatContext *avfc;
|
||||||
|
uint64_t readCount;
|
||||||
|
public:
|
||||||
|
Input();
|
||||||
|
~Input();
|
||||||
|
|
||||||
|
bool ReadSubtitle(const char *filename, const char *format, int pid);
|
||||||
|
bool ReadSubtitles(const char *filename);
|
||||||
|
bool Init(const char *filename);
|
||||||
|
bool UpdateTracks();
|
||||||
|
bool Play();
|
||||||
|
bool Stop();
|
||||||
|
bool Seek(float sec, bool absolute);
|
||||||
|
bool GetDuration(double &duration);
|
||||||
|
bool SwitchAudio(Track *track);
|
||||||
|
bool SwitchSubtitle(Track *track);
|
||||||
|
bool SwitchTeletext(Track *track);
|
||||||
|
bool SwitchVideo(Track *track);
|
||||||
|
bool GetMetadata(std::vector<std::string> &keys, std::vector<std::string> &values);
|
||||||
|
bool GetReadCount(uint64_t &readcount);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@@ -1,11 +1,10 @@
|
|||||||
#ifndef MANAGER_H_
|
#ifndef __MANAGER_H__
|
||||||
#define MANAGER_H_
|
#define __MANAGER_H__
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#include <OpenThreads/ScopedLock>
|
#include <OpenThreads/ScopedLock>
|
||||||
#include <OpenThreads/Thread>
|
#include <OpenThreads/Thread>
|
||||||
@@ -19,16 +18,7 @@ extern "C" {
|
|||||||
#include <libavutil/opt.h>
|
#include <libavutil/opt.h>
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef enum {
|
class Player;
|
||||||
MANAGER_ADD,
|
|
||||||
MANAGER_LIST,
|
|
||||||
MANAGER_GET,
|
|
||||||
MANAGER_GETNAME,
|
|
||||||
MANAGER_SET,
|
|
||||||
MANAGER_DEL,
|
|
||||||
MANAGER_GET_TRACK,
|
|
||||||
MANAGER_INIT_UPDATE
|
|
||||||
} ManagerCmd_t;
|
|
||||||
|
|
||||||
struct Track
|
struct Track
|
||||||
{
|
{
|
||||||
@@ -49,12 +39,15 @@ struct Track
|
|||||||
int ac3flags;
|
int ac3flags;
|
||||||
int type, mag, page; // for teletext
|
int type, mag, page; // for teletext
|
||||||
|
|
||||||
Track() : pid(-1), duration(-1), avfc(NULL), stream(NULL), inactive(0), is_static(0), ac3flags(-1) {}
|
Track() : pid(-1), duration(-1), avfc(NULL), stream(NULL), inactive(0), is_static(0), ac3flags(0) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class Manager
|
class Manager
|
||||||
{
|
{
|
||||||
|
friend class Player;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Player *context;
|
||||||
OpenThreads::Mutex mutex;
|
OpenThreads::Mutex mutex;
|
||||||
std::map<int,Track *> videoTracks, audioTracks, subtitleTracks, teletextTracks;
|
std::map<int,Track *> videoTracks, audioTracks, subtitleTracks, teletextTracks;
|
||||||
public:
|
public:
|
||||||
|
@@ -1,9 +1,10 @@
|
|||||||
#ifndef OUTPUT_H_
|
#ifndef __OUTPUT_H__
|
||||||
#define OUTPUT_H_
|
#define __OUTPUT_H__
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#include <OpenThreads/ScopedLock>
|
#include <OpenThreads/ScopedLock>
|
||||||
#include <OpenThreads/Thread>
|
#include <OpenThreads/Thread>
|
||||||
@@ -19,14 +20,19 @@ extern "C" {
|
|||||||
|
|
||||||
#include "writer.h"
|
#include "writer.h"
|
||||||
|
|
||||||
|
class Player;
|
||||||
|
|
||||||
class Output
|
class Output
|
||||||
{
|
{
|
||||||
|
friend class Player;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int videofd;
|
int videofd;
|
||||||
int audiofd;
|
int audiofd;
|
||||||
Writer *videoWriter, *audioWriter;
|
Writer *videoWriter, *audioWriter;
|
||||||
OpenThreads::Mutex audioMutex, videoMutex;
|
OpenThreads::Mutex audioMutex, videoMutex;
|
||||||
AVStream *audioStream, *videoStream;
|
AVStream *audioStream, *videoStream;
|
||||||
|
Player *context;
|
||||||
public:
|
public:
|
||||||
Output();
|
Output();
|
||||||
~Output();
|
~Output();
|
||||||
|
@@ -1,45 +1,82 @@
|
|||||||
#ifndef PLAYBACK_H_
|
#ifndef __PLAYBACK_H__
|
||||||
#define PLAYBACK_H_
|
#define __PLAYBACK_H__
|
||||||
#include <sys/types.h>
|
|
||||||
|
#include <stdint.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
typedef enum { PLAYBACK_OPEN, PLAYBACK_CLOSE, PLAYBACK_PLAY, PLAYBACK_STOP,
|
#include <OpenThreads/ScopedLock>
|
||||||
PLAYBACK_PAUSE, PLAYBACK_CONTINUE, PLAYBACK_FLUSH, PLAYBACK_TERM,
|
#include <OpenThreads/Thread>
|
||||||
PLAYBACK_FASTFORWARD, PLAYBACK_SEEK, PLAYBACK_SEEK_ABS,
|
#include <OpenThreads/Condition>
|
||||||
PLAYBACK_PTS, PLAYBACK_LENGTH, PLAYBACK_SWITCH_AUDIO,
|
|
||||||
PLAYBACK_SWITCH_SUBTITLE, PLAYBACK_METADATA, PLAYBACK_SLOWMOTION,
|
|
||||||
PLAYBACK_FASTBACKWARD, PLAYBACK_GET_FRAME_COUNT,
|
|
||||||
PLAYBACK_SWITCH_TELETEXT
|
|
||||||
} PlaybackCmd_t;
|
|
||||||
|
|
||||||
struct Player;
|
extern "C" {
|
||||||
|
#include <libavutil/avutil.h>
|
||||||
|
#include <libavutil/time.h>
|
||||||
|
#include <libavformat/avformat.h>
|
||||||
|
#include <libswresample/swresample.h>
|
||||||
|
#include <libavutil/opt.h>
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct PlaybackHandler_s {
|
class Player;
|
||||||
const char *Name;
|
class Input;
|
||||||
|
|
||||||
int fd;
|
class Playback {
|
||||||
|
friend class Player;
|
||||||
|
friend class Input;
|
||||||
|
|
||||||
unsigned char isHttp;
|
private:
|
||||||
|
Player *context;
|
||||||
|
|
||||||
unsigned char isPlaying;
|
bool isHttp;
|
||||||
unsigned char isPaused;
|
bool isPaused;
|
||||||
unsigned char isForwarding;
|
bool isCreationPhase;
|
||||||
unsigned char isCreationPhase;
|
|
||||||
|
|
||||||
int BackWard;
|
bool isSlowMotion;
|
||||||
int SlowMotion;
|
int Speed;
|
||||||
int Speed;
|
int AVSync;
|
||||||
int AVSync;
|
|
||||||
|
bool isVideo;
|
||||||
|
bool isAudio;
|
||||||
|
|
||||||
|
std::string url;
|
||||||
|
bool noprobe; /* hack: only minimal probing in av_find_stream_info */
|
||||||
|
|
||||||
|
int hasThreadStarted;
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool isForwarding;
|
||||||
|
bool isBackWard;
|
||||||
|
bool isPlaying;
|
||||||
|
bool abortPlayback;
|
||||||
|
bool abortRequested;
|
||||||
|
uint64_t readCount;
|
||||||
|
|
||||||
|
bool SwitchAudio(int pid);
|
||||||
|
bool SwitchVideo(int pid);
|
||||||
|
bool SwitchTeletext(int pid);
|
||||||
|
bool SwitchSubtitle(int pid);
|
||||||
|
bool GetPts(int64_t &pts);
|
||||||
|
bool GetFrameCount(int64_t &framecount);
|
||||||
|
bool GetDuration(double &duration);
|
||||||
|
bool GetMetadata(std::vector<std::string> &keys, std::vector<std::string> &values);
|
||||||
|
bool SlowMotion(int repeats);
|
||||||
|
bool FastBackward(int speed);
|
||||||
|
bool FastForward(int speed);
|
||||||
|
bool Open(const char *Url);
|
||||||
|
bool Close();
|
||||||
|
bool Play();
|
||||||
|
bool Pause();
|
||||||
|
bool Continue();
|
||||||
|
bool Stop();
|
||||||
|
bool Seek(float pos, bool absolute);
|
||||||
|
bool Terminate();
|
||||||
|
|
||||||
|
static void* SupervisorThread(void*);
|
||||||
|
|
||||||
|
Playback();
|
||||||
|
};
|
||||||
|
|
||||||
unsigned char isVideo;
|
|
||||||
unsigned char isAudio;
|
|
||||||
unsigned char abortRequested;
|
|
||||||
unsigned char abortPlayback;
|
|
||||||
|
|
||||||
int (*Command) ( Player *, PlaybackCmd_t, void *);
|
|
||||||
std::string uri;
|
|
||||||
unsigned char noprobe; /* hack: only minimal probing in av_find_stream_info */
|
|
||||||
unsigned long long readCount;
|
|
||||||
} PlaybackHandler_t;
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -1,25 +1,63 @@
|
|||||||
#ifndef COMMON_H_
|
#ifndef __PLAYER_H__
|
||||||
#define COMMON_H_
|
#define __PLAYER_H__
|
||||||
|
|
||||||
|
#include <OpenThreads/ScopedLock>
|
||||||
|
#include <OpenThreads/Thread>
|
||||||
|
#include <OpenThreads/Condition>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <libavutil/avutil.h>
|
||||||
|
#include <libavutil/time.h>
|
||||||
|
#include <libavformat/avformat.h>
|
||||||
|
#include <libswresample/swresample.h>
|
||||||
|
#include <libavutil/opt.h>
|
||||||
|
}
|
||||||
|
|
||||||
#include "container.h"
|
|
||||||
#include "output.h"
|
|
||||||
#include "manager.h"
|
|
||||||
#include "playback.h"
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
class Player {
|
#include <string>
|
||||||
public: //FIXME
|
#include <vector>
|
||||||
PlaybackHandler_t *playback;
|
#include <map>
|
||||||
ContainerHandler_t *container;
|
|
||||||
int64_t *currentAudioPtsP;
|
|
||||||
public:
|
|
||||||
Player();
|
|
||||||
~Player();
|
|
||||||
|
|
||||||
Output output;
|
#include "input.h"
|
||||||
Manager manager;
|
#include "output.h"
|
||||||
|
#include "manager.h"
|
||||||
|
#include "playback.h"
|
||||||
|
#include "player.h"
|
||||||
|
|
||||||
|
struct Chapter
|
||||||
|
{
|
||||||
|
std::string title;
|
||||||
|
double start;
|
||||||
|
double end;
|
||||||
};
|
};
|
||||||
|
|
||||||
int container_ffmpeg_update_tracks(Player * context, const char *filename);
|
class Player {
|
||||||
|
friend class Input;
|
||||||
|
friend class Output;
|
||||||
|
friend class Manager;
|
||||||
|
friend class Playback;
|
||||||
|
friend class cPlayback;
|
||||||
|
private:
|
||||||
|
Input input;
|
||||||
|
Output output;
|
||||||
|
Manager manager;
|
||||||
|
Playback playback;
|
||||||
|
OpenThreads::Mutex chapterMutex;
|
||||||
|
std::vector<Chapter> chapters;
|
||||||
|
public: //FIXME
|
||||||
|
int64_t *currentAudioPtsP;
|
||||||
|
public:
|
||||||
|
Player()
|
||||||
|
{
|
||||||
|
input.context = this;
|
||||||
|
output.context = this;
|
||||||
|
playback.context = this;
|
||||||
|
manager.context = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetChapters(std::vector<int> &positions, std::vector<std::string> &titles);
|
||||||
|
void SetChapters(std::vector<Chapter> &Chapters);
|
||||||
|
};
|
||||||
#endif
|
#endif
|
||||||
|
@@ -24,42 +24,59 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "manager.h"
|
#include "manager.h"
|
||||||
|
#include "player.h"
|
||||||
|
|
||||||
void Manager::addVideoTrack(Track &track)
|
void Manager::addVideoTrack(Track &track)
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> m_lock(mutex);
|
OpenThreads::ScopedLock<OpenThreads::Mutex> m_lock(mutex);
|
||||||
Track *t = new Track;
|
std::map<int,Track*>::iterator it = videoTracks.find(track.pid);
|
||||||
*t = track;
|
if (it == videoTracks.end()) {
|
||||||
videoTracks[track.pid] = t;
|
Track *t = new Track;
|
||||||
|
*t = track;
|
||||||
|
videoTracks[track.pid] = t;
|
||||||
|
} else
|
||||||
|
*it->second = track;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::addAudioTrack(Track &track)
|
void Manager::addAudioTrack(Track &track)
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> m_lock(mutex);
|
OpenThreads::ScopedLock<OpenThreads::Mutex> m_lock(mutex);
|
||||||
Track *t = new Track;
|
std::map<int,Track*>::iterator it = audioTracks.find(track.pid);
|
||||||
*t = track;
|
if (it == audioTracks.end()) {
|
||||||
audioTracks[track.pid] = t;
|
Track *t = new Track;
|
||||||
|
*t = track;
|
||||||
|
audioTracks[track.pid] = t;
|
||||||
|
} else
|
||||||
|
*it->second = track;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::addSubtitleTrack(Track &track)
|
void Manager::addSubtitleTrack(Track &track)
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> m_lock(mutex);
|
OpenThreads::ScopedLock<OpenThreads::Mutex> m_lock(mutex);
|
||||||
Track *t = new Track;
|
std::map<int,Track*>::iterator it = subtitleTracks.find(track.pid);
|
||||||
*t = track;
|
if (it == subtitleTracks.end()) {
|
||||||
subtitleTracks[track.pid] = t;
|
Track *t = new Track;
|
||||||
|
*t = track;
|
||||||
|
subtitleTracks[track.pid] = t;
|
||||||
|
} else
|
||||||
|
*it->second = track;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::addTeletextTrack(Track &track)
|
void Manager::addTeletextTrack(Track &track)
|
||||||
{
|
{
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> m_lock(mutex);
|
OpenThreads::ScopedLock<OpenThreads::Mutex> m_lock(mutex);
|
||||||
Track *t = new Track;
|
std::map<int,Track*>::iterator it = teletextTracks.find(track.pid);
|
||||||
*t = track;
|
if (it == teletextTracks.end()) {
|
||||||
teletextTracks[track.pid] = t;
|
Track *t = new Track;
|
||||||
|
*t = track;
|
||||||
|
teletextTracks[track.pid] = t;
|
||||||
|
} else
|
||||||
|
*it->second = track;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Track> Manager::getVideoTracks()
|
std::vector<Track> Manager::getVideoTracks()
|
||||||
{
|
{
|
||||||
// input.UpdateTracks();
|
context->input.UpdateTracks();
|
||||||
std::vector<Track> res;
|
std::vector<Track> res;
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> m_lock(mutex);
|
OpenThreads::ScopedLock<OpenThreads::Mutex> m_lock(mutex);
|
||||||
for(std::map<int,Track*>::iterator it = videoTracks.begin(); it != videoTracks.end(); ++it)
|
for(std::map<int,Track*>::iterator it = videoTracks.begin(); it != videoTracks.end(); ++it)
|
||||||
@@ -70,7 +87,7 @@ std::vector<Track> Manager::getVideoTracks()
|
|||||||
|
|
||||||
std::vector<Track> Manager::getAudioTracks()
|
std::vector<Track> Manager::getAudioTracks()
|
||||||
{
|
{
|
||||||
// input.UpdateTracks();
|
context->input.UpdateTracks();
|
||||||
std::vector<Track> res;
|
std::vector<Track> res;
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> m_lock(mutex);
|
OpenThreads::ScopedLock<OpenThreads::Mutex> m_lock(mutex);
|
||||||
for(std::map<int,Track*>::iterator it = audioTracks.begin(); it != audioTracks.end(); ++it)
|
for(std::map<int,Track*>::iterator it = audioTracks.begin(); it != audioTracks.end(); ++it)
|
||||||
@@ -81,7 +98,7 @@ std::vector<Track> Manager::getAudioTracks()
|
|||||||
|
|
||||||
std::vector<Track> Manager::getSubtitleTracks()
|
std::vector<Track> Manager::getSubtitleTracks()
|
||||||
{
|
{
|
||||||
// input.UpdateTracks();
|
context->input.UpdateTracks();
|
||||||
std::vector<Track> res;
|
std::vector<Track> res;
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> m_lock(mutex);
|
OpenThreads::ScopedLock<OpenThreads::Mutex> m_lock(mutex);
|
||||||
for(std::map<int,Track*>::iterator it = subtitleTracks.begin(); it != subtitleTracks.end(); ++it)
|
for(std::map<int,Track*>::iterator it = subtitleTracks.begin(); it != subtitleTracks.end(); ++it)
|
||||||
@@ -92,7 +109,7 @@ std::vector<Track> Manager::getSubtitleTracks()
|
|||||||
|
|
||||||
std::vector<Track> Manager::getTeletextTracks()
|
std::vector<Track> Manager::getTeletextTracks()
|
||||||
{
|
{
|
||||||
// input.UpdateTracks();
|
context->input.UpdateTracks();
|
||||||
std::vector<Track> res;
|
std::vector<Track> res;
|
||||||
OpenThreads::ScopedLock<OpenThreads::Mutex> m_lock(mutex);
|
OpenThreads::ScopedLock<OpenThreads::Mutex> m_lock(mutex);
|
||||||
for(std::map<int,Track*>::iterator it = teletextTracks.begin(); it != teletextTracks.end(); ++it)
|
for(std::map<int,Track*>::iterator it = teletextTracks.begin(); it != teletextTracks.end(); ++it)
|
||||||
|
@@ -23,361 +23,268 @@
|
|||||||
#include "player.h"
|
#include "player.h"
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
|
|
||||||
/* ***************************** */
|
|
||||||
/* Makros/Constants */
|
|
||||||
/* ***************************** */
|
|
||||||
|
|
||||||
#define PLAYBACK_DEBUG
|
|
||||||
|
|
||||||
static short debug_level = 20;
|
|
||||||
|
|
||||||
static const char *FILENAME = "playback.c";
|
|
||||||
#ifdef PLAYBACK_DEBUG
|
|
||||||
#define playback_printf(level, fmt, x...) do { \
|
|
||||||
if (debug_level >= level) printf("[%s:%s] " fmt, FILENAME, __FUNCTION__, ## x); } while (0)
|
|
||||||
#else
|
|
||||||
#define playback_printf(level, fmt, x...)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef PLAYBACK_SILENT
|
|
||||||
#define playback_err(fmt, x...) do { printf("[%s:%s] " fmt, FILENAME, __FUNCTION__, ## x); } while (0)
|
|
||||||
#else
|
|
||||||
#define playback_err(fmt, x...)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define cERR_PLAYBACK_NO_ERROR 0
|
|
||||||
#define cERR_PLAYBACK_ERROR -1
|
|
||||||
|
|
||||||
#define cMaxSpeed_ff 128 /* fixme: revise */
|
#define cMaxSpeed_ff 128 /* fixme: revise */
|
||||||
#define cMaxSpeed_fr -320 /* fixme: revise */
|
#define cMaxSpeed_fr -320 /* fixme: revise */
|
||||||
|
|
||||||
/* ***************************** */
|
|
||||||
/* Varaibles */
|
|
||||||
/* ***************************** */
|
|
||||||
|
|
||||||
static pthread_t supervisorThread;
|
static pthread_t supervisorThread;
|
||||||
static int hasThreadStarted = 0;
|
|
||||||
|
|
||||||
/* ***************************** */
|
Playback::Playback()
|
||||||
/* Prototypes */
|
|
||||||
/* ***************************** */
|
|
||||||
static int PlaybackTerminate(Player * context);
|
|
||||||
|
|
||||||
/* ***************************** */
|
|
||||||
/* MISC Functions */
|
|
||||||
/* ***************************** */
|
|
||||||
|
|
||||||
/* **************************** */
|
|
||||||
/* Supervisor Thread */
|
|
||||||
/* **************************** */
|
|
||||||
|
|
||||||
static void *SupervisorThread(void *arg)
|
|
||||||
{
|
{
|
||||||
Player *context = (Player *) arg;
|
hasThreadStarted = 0;
|
||||||
hasThreadStarted = 1;
|
|
||||||
|
|
||||||
playback_printf(10, ">\n");
|
|
||||||
|
|
||||||
while (context && context->playback && context->playback->isPlaying
|
|
||||||
&& !(context->playback->abortRequested | context->playback->abortPlayback))
|
|
||||||
usleep(100000);
|
|
||||||
|
|
||||||
playback_printf(10, "<\n");
|
|
||||||
|
|
||||||
hasThreadStarted = 2;
|
|
||||||
PlaybackTerminate(context);
|
|
||||||
|
|
||||||
playback_printf(0, "terminating\n");
|
|
||||||
hasThreadStarted = 0;
|
|
||||||
pthread_exit(NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ***************************** */
|
void *Playback::SupervisorThread(void *arg)
|
||||||
/* Functions */
|
|
||||||
/* ***************************** */
|
|
||||||
|
|
||||||
static int PlaybackStop(Player * context);
|
|
||||||
|
|
||||||
static int PlaybackOpen(Player * context, char *uri)
|
|
||||||
{
|
{
|
||||||
if (context->playback->isPlaying)
|
Playback *me = (Playback *) arg;
|
||||||
PlaybackStop(context);
|
me->hasThreadStarted = 1;
|
||||||
|
|
||||||
playback_printf(10, "URI=%s\n", uri);
|
me->context->input.Play();
|
||||||
|
me->hasThreadStarted = 2;
|
||||||
|
me->Terminate();
|
||||||
|
|
||||||
if (context->playback->isPlaying) { // shouldn't happen
|
fprintf(stderr, "terminating\n");
|
||||||
playback_err("playback already running\n");
|
me->hasThreadStarted = 0;
|
||||||
return cERR_PLAYBACK_ERROR;
|
pthread_exit(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Playback::Open(const char *Url)
|
||||||
|
{
|
||||||
|
if (context->playback.isPlaying)
|
||||||
|
Stop(); // shouldn't happen. Most definitely a bug
|
||||||
|
|
||||||
|
fprintf(stderr, "URL=%s\n", Url);
|
||||||
|
|
||||||
|
if (context->playback.isPlaying) { // shouldn't happen
|
||||||
|
fprintf(stderr, "playback already running\n");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
context->playback->isHttp = 0;
|
context->playback.isHttp = 0;
|
||||||
|
|
||||||
if (!strncmp("file://", uri, 7) || !strncmp("myts://", uri, 7)) {
|
if (!strncmp("file://", Url, 7) || !strncmp("myts://", Url, 7)) {
|
||||||
if (!strncmp("myts://", uri, 7)) {
|
if (!strncmp("myts://", Url, 7)) {
|
||||||
context->playback->uri = "file";
|
context->playback.url = "file";
|
||||||
context->playback->uri += (uri + 4);
|
context->playback.url += (Url + 4);
|
||||||
context->playback->noprobe = 1;
|
context->playback.noprobe = 1;
|
||||||
} else {
|
} else {
|
||||||
context->playback->noprobe = 0;
|
context->playback.noprobe = 0;
|
||||||
context->playback->uri = uri;
|
context->playback.url = Url;
|
||||||
}
|
}
|
||||||
} else if (strstr(uri, "://")) {
|
} else if (strstr(Url, "://")) {
|
||||||
context->playback->isHttp = 1;
|
context->playback.isHttp = 1;
|
||||||
if (!strncmp("mms://", uri, 6)) {
|
if (!strncmp("mms://", Url, 6)) {
|
||||||
context->playback->uri = "mmst";
|
context->playback.url = "mmst";
|
||||||
context->playback->uri += (uri + 3);
|
context->playback.url += (Url + 3);
|
||||||
} else
|
} else
|
||||||
context->playback->uri = uri;
|
context->playback.url = Url;
|
||||||
} else {
|
} else {
|
||||||
playback_err("Unknown stream (%s)\n", uri);
|
fprintf(stderr, "Unknown stream (%s)\n", Url);
|
||||||
return cERR_PLAYBACK_ERROR;
|
return false;
|
||||||
}
|
}
|
||||||
context->manager.clearTracks();
|
context->manager.clearTracks();
|
||||||
|
|
||||||
if ((context->container->Command(context, CONTAINER_ADD, NULL) < 0)
|
if (!context->input.Init(context->playback.url.c_str()))
|
||||||
|| (!context->container->selectedContainer)
|
return false;
|
||||||
|| (context->container->selectedContainer->Command(context, CONTAINER_INIT, context->playback->uri.c_str()) < 0))
|
|
||||||
return cERR_PLAYBACK_ERROR;
|
|
||||||
|
|
||||||
playback_printf(10, "exiting with value 0\n");
|
fprintf(stderr, "exiting with value 0\n");
|
||||||
|
|
||||||
return cERR_PLAYBACK_NO_ERROR;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int PlaybackClose(Player * context)
|
bool Playback::Close()
|
||||||
{
|
{
|
||||||
int ret = cERR_PLAYBACK_NO_ERROR;
|
bool ret = true;
|
||||||
|
|
||||||
playback_printf(10, "\n");
|
context->playback.isPaused = 0;
|
||||||
|
context->playback.isPlaying = 0;
|
||||||
if (context->container->Command(context, CONTAINER_DEL, NULL) < 0) {
|
context->playback.isForwarding = 0;
|
||||||
playback_err("container delete failed\n");
|
context->playback.isBackWard = 0;
|
||||||
}
|
context->playback.isSlowMotion = 0;
|
||||||
|
context->playback.Speed = 0;
|
||||||
|
context->playback.url.clear();
|
||||||
context->playback->isPaused = 0;
|
|
||||||
context->playback->isPlaying = 0;
|
|
||||||
context->playback->isForwarding = 0;
|
|
||||||
context->playback->BackWard = 0;
|
|
||||||
context->playback->SlowMotion = 0;
|
|
||||||
context->playback->Speed = 0;
|
|
||||||
context->playback->uri.clear();
|
|
||||||
|
|
||||||
playback_printf(10, "exiting with value %d\n", ret);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int PlaybackPlay(Player * context)
|
bool Playback::Play()
|
||||||
{
|
{
|
||||||
pthread_attr_t attr;
|
pthread_attr_t attr;
|
||||||
int ret = cERR_PLAYBACK_NO_ERROR;
|
bool ret = true;
|
||||||
|
|
||||||
playback_printf(10, "\n");
|
if (!context->playback.isPlaying) {
|
||||||
|
context->playback.AVSync = 1;
|
||||||
if (!context->playback->isPlaying) {
|
|
||||||
context->playback->AVSync = 1;
|
|
||||||
context->output.AVSync(true);
|
context->output.AVSync(true);
|
||||||
|
|
||||||
context->playback->isCreationPhase = 1; // allows the created thread to go into wait mode
|
context->playback.isCreationPhase = 1; // allows the created thread to go into wait mode
|
||||||
ret = context->output.Play();
|
ret = context->output.Play();
|
||||||
|
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
context->playback->isCreationPhase = 0; // allow thread to go into next state
|
context->playback.isCreationPhase = 0; // allow thread to go into next state
|
||||||
} else {
|
} else {
|
||||||
context->playback->isPlaying = 1;
|
context->playback.isPlaying = 1;
|
||||||
context->playback->isPaused = 0;
|
context->playback.isPaused = 0;
|
||||||
context->playback->isForwarding = 0;
|
context->playback.isForwarding = 0;
|
||||||
if (context->playback->BackWard) {
|
if (context->playback.isBackWard) {
|
||||||
context->playback->BackWard = 0;
|
context->playback.isBackWard = 0;
|
||||||
context->output.Mute(false);
|
context->output.Mute(false);
|
||||||
}
|
}
|
||||||
context->playback->SlowMotion = 0;
|
context->playback.isSlowMotion = 0;
|
||||||
context->playback->Speed = 1;
|
context->playback.Speed = 1;
|
||||||
|
|
||||||
if (hasThreadStarted == 0) {
|
if (hasThreadStarted == 0) {
|
||||||
int error;
|
int error;
|
||||||
pthread_attr_init(&attr);
|
pthread_attr_init(&attr);
|
||||||
pthread_attr_setdetachstate(&attr,
|
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||||
PTHREAD_CREATE_DETACHED);
|
|
||||||
|
|
||||||
if ((error =
|
if ((error = pthread_create(&supervisorThread, &attr, SupervisorThread, &context->playback))) {
|
||||||
pthread_create(&supervisorThread, &attr, SupervisorThread, context)) != 0) {
|
fprintf(stderr, "Error creating thread, error:%d:%s\n", error, strerror(error));
|
||||||
playback_printf(10,
|
|
||||||
"Error creating thread, error:%d:%s\n",
|
|
||||||
error, strerror(error));
|
|
||||||
|
|
||||||
ret = cERR_PLAYBACK_ERROR;
|
ret = false;
|
||||||
} else {
|
} else {
|
||||||
playback_printf(10, "Created thread\n");
|
fprintf(stderr, "Created thread\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
playback_printf(10, "clearing isCreationPhase!\n");
|
fprintf(stderr, "clearing isCreationPhase!\n");
|
||||||
|
|
||||||
context->playback->isCreationPhase = 0; // allow thread to go into next state
|
|
||||||
|
|
||||||
ret =
|
|
||||||
context->container->selectedContainer->Command(context,
|
|
||||||
CONTAINER_PLAY,
|
|
||||||
NULL);
|
|
||||||
if (ret != 0) {
|
|
||||||
playback_err("CONTAINER_PLAY failed!\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
context->playback.isCreationPhase = 0; // allow thread to go into next state
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
playback_err("playback already running\n");
|
fprintf(stderr,"playback already running\n");
|
||||||
ret = cERR_PLAYBACK_ERROR;
|
ret = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
playback_printf(10, "exiting with value %d\n", ret);
|
fprintf(stderr, "exiting with value %d\n", ret);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int PlaybackPause(Player * context)
|
bool Playback::Pause()
|
||||||
{
|
{
|
||||||
int ret = cERR_PLAYBACK_NO_ERROR;
|
bool ret = true;
|
||||||
|
|
||||||
playback_printf(10, "\n");
|
if (context->playback.isPlaying && !context->playback.isPaused) {
|
||||||
|
|
||||||
if (context->playback->isPlaying && !context->playback->isPaused) {
|
if (context->playback.isSlowMotion)
|
||||||
|
|
||||||
if (context->playback->SlowMotion)
|
|
||||||
context->output.Clear();
|
context->output.Clear();
|
||||||
|
|
||||||
context->output.Pause();
|
context->output.Pause();
|
||||||
|
|
||||||
context->playback->isPaused = 1;
|
context->playback.isPaused = 1;
|
||||||
//context->playback->isPlaying = 1;
|
//context->playback.isPlaying = 1;
|
||||||
context->playback->isForwarding = 0;
|
context->playback.isForwarding = 0;
|
||||||
if (context->playback->BackWard) {
|
if (context->playback.isBackWard) {
|
||||||
context->playback->BackWard = 0;
|
context->playback.isBackWard = 0;
|
||||||
context->output.Mute(false);
|
context->output.Mute(false);
|
||||||
}
|
}
|
||||||
context->playback->SlowMotion = 0;
|
context->playback.isSlowMotion = 0;
|
||||||
context->playback->Speed = 1;
|
context->playback.Speed = 1;
|
||||||
} else {
|
} else {
|
||||||
playback_err("playback not playing or already in pause mode\n");
|
fprintf(stderr,"playback not playing or already in pause mode\n");
|
||||||
ret = cERR_PLAYBACK_ERROR;
|
ret = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
playback_printf(10, "exiting with value %d\n", ret);
|
fprintf(stderr, "exiting with value %d\n", ret);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int PlaybackContinue(Player * context)
|
bool Playback::Continue()
|
||||||
{
|
{
|
||||||
int ret = cERR_PLAYBACK_NO_ERROR;
|
int ret = true;
|
||||||
|
|
||||||
playback_printf(10, "\n");
|
if (context->playback.isPlaying && (context->playback.isPaused || context->playback.isForwarding
|
||||||
|
|| context->playback.isBackWard || context->playback.isSlowMotion)) {
|
||||||
|
|
||||||
if (context->playback->isPlaying &&
|
if (context->playback.isSlowMotion)
|
||||||
(context->playback->isPaused || context->playback->isForwarding
|
|
||||||
|| context->playback->BackWard
|
|
||||||
|| context->playback->SlowMotion)) {
|
|
||||||
|
|
||||||
if (context->playback->SlowMotion)
|
|
||||||
context->output.Clear();
|
context->output.Clear();
|
||||||
|
|
||||||
context->output.Continue();
|
context->output.Continue();
|
||||||
|
|
||||||
context->playback->isPaused = 0;
|
context->playback.isPaused = 0;
|
||||||
//context->playback->isPlaying = 1;
|
//context->playback.isPlaying = 1;
|
||||||
context->playback->isForwarding = 0;
|
context->playback.isForwarding = 0;
|
||||||
if (context->playback->BackWard) {
|
if (context->playback.isBackWard) {
|
||||||
context->playback->BackWard = 0;
|
context->playback.isBackWard = 0;
|
||||||
context->output.Mute(false);
|
context->output.Mute(false);
|
||||||
}
|
}
|
||||||
context->playback->SlowMotion = 0;
|
context->playback.isSlowMotion = 0;
|
||||||
context->playback->Speed = 1;
|
context->playback.Speed = 1;
|
||||||
} else {
|
} else {
|
||||||
playback_err("continue not possible\n");
|
fprintf(stderr,"continue not possible\n");
|
||||||
ret = cERR_PLAYBACK_ERROR;
|
ret = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
playback_printf(10, "exiting with value %d\n", ret);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int PlaybackStop(Player * context)
|
bool Playback::Stop()
|
||||||
{
|
{
|
||||||
int ret = cERR_PLAYBACK_NO_ERROR;
|
bool ret = true;
|
||||||
int wait_time = 20;
|
int wait_time = 20;
|
||||||
|
|
||||||
playback_printf(10, "\n");
|
if (context->playback.isPlaying) {
|
||||||
|
|
||||||
if (context && context->playback && context->playback->isPlaying) {
|
context->playback.isPaused = 0;
|
||||||
|
context->playback.isPlaying = 0;
|
||||||
context->playback->isPaused = 0;
|
context->playback.isForwarding = 0;
|
||||||
context->playback->isPlaying = 0;
|
if (context->playback.isBackWard) {
|
||||||
context->playback->isForwarding = 0;
|
context->playback.isBackWard = 0;
|
||||||
if (context->playback->BackWard) {
|
|
||||||
context->playback->BackWard = 0;
|
|
||||||
context->output.Mute(false);
|
context->output.Mute(false);
|
||||||
}
|
}
|
||||||
context->playback->SlowMotion = 0;
|
context->playback.isSlowMotion = 0;
|
||||||
context->playback->Speed = 0;
|
context->playback.Speed = 0;
|
||||||
|
|
||||||
context->output.Stop();
|
context->output.Stop();
|
||||||
context->container->selectedContainer->Command(context, CONTAINER_STOP, NULL);
|
context->input.Stop();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
playback_err("stop not possible\n");
|
fprintf(stderr,"stop not possible\n");
|
||||||
ret = cERR_PLAYBACK_ERROR;
|
ret = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((hasThreadStarted == 1) && (--wait_time) > 0) {
|
while ((hasThreadStarted == 1) && (--wait_time) > 0) {
|
||||||
playback_printf(10,
|
fprintf(stderr, "Waiting for supervisor thread to terminate itself, will try another %d times\n", wait_time);
|
||||||
"Waiting for supervisor thread to terminate itself, will try another %d times\n",
|
|
||||||
wait_time);
|
|
||||||
|
|
||||||
usleep(100000);
|
usleep(100000);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wait_time == 0) {
|
if (wait_time == 0) {
|
||||||
playback_err("Timeout waiting for thread!\n");
|
fprintf(stderr,"Timeout waiting for thread!\n");
|
||||||
|
|
||||||
ret = cERR_PLAYBACK_ERROR;
|
ret = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
playback_printf(10, "exiting with value %d\n", ret);
|
fprintf(stderr, "exiting with value %d\n", ret);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int PlaybackTerminate(Player * context)
|
// FIXME
|
||||||
|
bool Playback::Terminate()
|
||||||
{
|
{
|
||||||
int ret = cERR_PLAYBACK_NO_ERROR;
|
bool ret = true;
|
||||||
int wait_time = 20;
|
int wait_time = 20;
|
||||||
|
|
||||||
playback_printf(20, "\n");
|
fprintf(stderr, "\n");
|
||||||
|
|
||||||
if (context && context->playback && context->playback->isPlaying) {
|
if (context->playback.isPlaying) {
|
||||||
//First Flush and than delete container, else e2 cant read length of file anymore
|
|
||||||
|
|
||||||
if (!context->playback->abortRequested && !context->output.Flush()) {
|
if (!context->playback.abortRequested && !context->output.Flush()) {
|
||||||
playback_err("failed to flush output.\n");
|
fprintf(stderr,"failed to flush output.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
ret =
|
ret = context->input.Stop();
|
||||||
context->container->selectedContainer->Command(context,
|
context->playback.isPaused = 0;
|
||||||
CONTAINER_STOP,
|
context->playback.isPlaying = 0;
|
||||||
NULL);
|
context->playback.isForwarding = 0;
|
||||||
context->playback->isPaused = 0;
|
context->playback.isBackWard = 0;
|
||||||
context->playback->isPlaying = 0;
|
context->playback.isSlowMotion = 0;
|
||||||
context->playback->isForwarding = 0;
|
context->playback.Speed = 0;
|
||||||
context->playback->BackWard = 0;
|
|
||||||
context->playback->SlowMotion = 0;
|
|
||||||
context->playback->Speed = 0;
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
playback_err("%p %p %d\n", context, context->playback,
|
fprintf(stderr,"%p %d\n", context, context->playback.isPlaying);
|
||||||
context->playback->isPlaying);
|
|
||||||
|
|
||||||
/* fixme: konfetti: we should return an error here but this seems to be a condition which
|
/* fixme: konfetti: we should return an error here but this seems to be a condition which
|
||||||
* can happen and is not a real error, which leads to a dead neutrino. should investigate
|
* can happen and is not a real error, which leads to a dead neutrino. should investigate
|
||||||
@@ -386,376 +293,190 @@ static int PlaybackTerminate(Player * context)
|
|||||||
}
|
}
|
||||||
|
|
||||||
while ((hasThreadStarted == 1) && (--wait_time) > 0) {
|
while ((hasThreadStarted == 1) && (--wait_time) > 0) {
|
||||||
playback_printf(10,
|
fprintf(stderr, "Waiting for supervisor thread to terminate itself, will try another %d times\n", wait_time);
|
||||||
"Waiting for supervisor thread to terminate itself, will try another %d times\n",
|
|
||||||
wait_time);
|
|
||||||
|
|
||||||
usleep(100000);
|
usleep(100000);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wait_time == 0) {
|
if (wait_time == 0) {
|
||||||
playback_err("Timeout waiting for thread!\n");
|
fprintf(stderr,"Timeout waiting for thread!\n");
|
||||||
|
|
||||||
ret = cERR_PLAYBACK_ERROR;
|
ret = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
playback_printf(20, "exiting with value %d\n", ret);
|
fprintf(stderr, "exiting with value %d\n", ret);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int PlaybackFastForward(Player * context, int *speed)
|
bool Playback::FastForward(int speed)
|
||||||
{
|
{
|
||||||
int ret = cERR_PLAYBACK_NO_ERROR;
|
int ret = true;
|
||||||
|
|
||||||
playback_printf(10, "speed %d\n", *speed);
|
|
||||||
|
|
||||||
/* Audio only forwarding not supported */
|
/* Audio only forwarding not supported */
|
||||||
if (context->playback->isVideo && !context->playback->isHttp
|
if (context->playback.isVideo && !context->playback.isHttp && !context->playback.isBackWard
|
||||||
&& !context->playback->BackWard && (!context->playback->isPaused
|
&& (!context->playback.isPaused || context-> playback.isPlaying)) {
|
||||||
|| context->
|
|
||||||
playback->isPlaying)) {
|
|
||||||
|
|
||||||
if ((*speed <= 0) || (*speed > cMaxSpeed_ff)) {
|
if ((speed <= 0) || (speed > cMaxSpeed_ff)) {
|
||||||
playback_err("speed %d out of range (1 - %d) \n", *speed,
|
fprintf(stderr, "speed %d out of range (1 - %d) \n", speed, cMaxSpeed_ff);
|
||||||
cMaxSpeed_ff);
|
return false;
|
||||||
return cERR_PLAYBACK_ERROR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
context->playback->isForwarding = 1;
|
context->playback.isForwarding = 1;
|
||||||
context->playback->Speed = *speed;
|
context->playback.Speed = speed;
|
||||||
|
context->output.FastForward(speed);
|
||||||
playback_printf(20, "Speed: %d x {%d}\n", *speed,
|
|
||||||
context->playback->Speed);
|
|
||||||
|
|
||||||
context->output.FastForward(*speed);
|
|
||||||
} else {
|
} else {
|
||||||
playback_err("fast forward not possible\n");
|
fprintf(stderr,"fast forward not possible\n");
|
||||||
ret = cERR_PLAYBACK_ERROR;
|
ret = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
playback_printf(10, "exiting with value %d\n", ret);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int PlaybackFastBackward(Player * context, int *speed)
|
bool Playback::FastBackward(int speed)
|
||||||
{
|
{
|
||||||
int ret = cERR_PLAYBACK_NO_ERROR;
|
bool ret = true;
|
||||||
|
|
||||||
playback_printf(10, "speed = %d\n", *speed);
|
|
||||||
|
|
||||||
/* Audio only reverse play not supported */
|
/* Audio only reverse play not supported */
|
||||||
if (context->playback->isVideo && !context->playback->isForwarding
|
if (context->playback.isVideo && !context->playback.isForwarding
|
||||||
&& (!context->playback->isPaused
|
&& (!context->playback.isPaused || context->playback.isPlaying)) {
|
||||||
|| context->playback->isPlaying)) {
|
|
||||||
|
|
||||||
if ((*speed > 0) || (*speed < cMaxSpeed_fr)) {
|
if ((speed > 0) || (speed < cMaxSpeed_fr)) {
|
||||||
playback_err("speed %d out of range (0 - %d) \n", *speed,
|
fprintf(stderr, "speed %d out of range (0 - %d) \n", speed, cMaxSpeed_fr);
|
||||||
cMaxSpeed_fr);
|
return false;
|
||||||
return cERR_PLAYBACK_ERROR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*speed == 0) {
|
if (speed == 0) {
|
||||||
context->playback->BackWard = 0;
|
context->playback.isBackWard = false;
|
||||||
context->playback->Speed = 0; /* reverse end */
|
context->playback.Speed = false; /* reverse end */
|
||||||
} else {
|
} else {
|
||||||
context->playback->Speed = *speed;
|
context->playback.Speed = speed;
|
||||||
context->playback->BackWard = 1;
|
context->playback.isBackWard = true;
|
||||||
|
|
||||||
playback_printf(1, "S %d B %d\n", context->playback->Speed, context->playback->BackWard);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
context->output.Clear();
|
context->output.Clear();
|
||||||
#if 0
|
#if 0
|
||||||
if (context->output->Command(context, OUTPUT_REVERSE, NULL) < 0) {
|
if (context->output->Command(context, OUTPUT_REVERSE, NULL) < 0) {
|
||||||
playback_err("OUTPUT_REVERSE failed\n");
|
fprintf(stderr,"OUTPUT_REVERSE failed\n");
|
||||||
context->playback->BackWard = 0;
|
context->playback.isBackWard = 0;
|
||||||
context->playback->Speed = 1;
|
context->playback.Speed = 1;
|
||||||
ret = cERR_PLAYBACK_ERROR;
|
ret = false;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
playback_err("fast backward not possible\n");
|
fprintf(stderr,"fast backward not possible\n");
|
||||||
ret = cERR_PLAYBACK_ERROR;
|
ret = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context->playback->BackWard)
|
if (context->playback.isBackWard)
|
||||||
context->output.Mute(true);
|
context->output.Mute(true);
|
||||||
playback_printf(10, "exiting with value %d\n", ret);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int PlaybackSlowMotion(Player * context, int *speed)
|
bool Playback::SlowMotion(int repeats)
|
||||||
{
|
{
|
||||||
int ret = cERR_PLAYBACK_NO_ERROR;
|
if (context->playback.isVideo && !context->playback.isHttp && context->playback.isPlaying) {
|
||||||
|
if (context->playback.isPaused)
|
||||||
|
Continue();
|
||||||
|
|
||||||
playback_printf(10, "\n");
|
switch (repeats) {
|
||||||
|
case 2:
|
||||||
|
case 4:
|
||||||
|
case 8:
|
||||||
|
context->playback.isSlowMotion = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
repeats = 0;
|
||||||
|
}
|
||||||
|
|
||||||
//Audio only forwarding not supported
|
context->output.SlowMotion(repeats);
|
||||||
if (context->playback->isVideo && !context->playback->isHttp
|
return true;
|
||||||
&& context->playback->isPlaying) {
|
|
||||||
if (context->playback->isPaused)
|
|
||||||
PlaybackContinue(context);
|
|
||||||
|
|
||||||
switch (*speed) {
|
|
||||||
case 2:
|
|
||||||
context->playback->SlowMotion = 2;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
context->playback->SlowMotion = 4;
|
|
||||||
break;
|
|
||||||
case 8:
|
|
||||||
context->playback->SlowMotion = 8;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
fprintf(stderr, "slowmotion not possible\n");
|
||||||
playback_printf(20, "SlowMotion: %d x {%d}\n", *speed,
|
return false;
|
||||||
context->playback->SlowMotion);
|
|
||||||
|
|
||||||
context->output.SlowMotion(*speed);
|
|
||||||
} else {
|
|
||||||
playback_err("slowmotion not possible\n");
|
|
||||||
ret = cERR_PLAYBACK_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
playback_printf(10, "exiting with value %d\n", ret);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int PlaybackSeek(Player * context, float *pos, int absolute)
|
bool Playback::Seek(float pos, bool absolute)
|
||||||
{
|
{
|
||||||
int ret = cERR_PLAYBACK_NO_ERROR;
|
|
||||||
|
|
||||||
playback_printf(10, "pos: %f\n", *pos);
|
|
||||||
|
|
||||||
context->output.Clear();
|
context->output.Clear();
|
||||||
|
return context->input.Seek(pos, absolute);
|
||||||
if (absolute)
|
|
||||||
context->container->selectedContainer->Command(context, CONTAINER_SEEK_ABS, (const char *)pos);
|
|
||||||
else
|
|
||||||
context->container->selectedContainer->Command(context, CONTAINER_SEEK, (const char *)pos);
|
|
||||||
|
|
||||||
playback_printf(10, "exiting with value %d\n", ret);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int PlaybackPts(Player * context, int64_t &pts)
|
bool Playback::GetPts(int64_t &pts)
|
||||||
{
|
{
|
||||||
int ret = cERR_PLAYBACK_NO_ERROR;
|
if (context->playback.isPlaying)
|
||||||
|
return context->output.GetPts(pts);
|
||||||
playback_printf(20, "\n");
|
return false;
|
||||||
|
|
||||||
pts = 0;
|
|
||||||
|
|
||||||
if (context->playback->isPlaying) {
|
|
||||||
ret = !context->output.GetPts(pts);
|
|
||||||
} else {
|
|
||||||
playback_err("not possible\n");
|
|
||||||
ret = cERR_PLAYBACK_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
playback_printf(20, "exiting with value %d\n", ret);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int PlaybackGetFrameCount(Player * context, int64_t &frameCount)
|
bool Playback::GetFrameCount(int64_t &frameCount)
|
||||||
{
|
{
|
||||||
int ret = cERR_PLAYBACK_NO_ERROR;
|
if (context->playback.isPlaying)
|
||||||
|
return context->output.GetFrameCount(frameCount);
|
||||||
playback_printf(20, "\n");
|
return false;
|
||||||
|
|
||||||
frameCount = 0;
|
|
||||||
|
|
||||||
if (context->playback->isPlaying) {
|
|
||||||
ret = !context->output.GetFrameCount(frameCount);
|
|
||||||
} else {
|
|
||||||
playback_err("not possible\n");
|
|
||||||
ret = cERR_PLAYBACK_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
playback_printf(20, "exiting with value %d\n", ret);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int PlaybackLength(Player * context, double *length)
|
bool Playback::GetDuration(double &duration)
|
||||||
{
|
{
|
||||||
int ret = cERR_PLAYBACK_NO_ERROR;
|
duration = -1;
|
||||||
|
if (context->playback.isPlaying)
|
||||||
playback_printf(20, "\n");
|
return context->input.GetDuration(duration);
|
||||||
|
return false;
|
||||||
*length = -1;
|
|
||||||
|
|
||||||
if (context->playback->isPlaying) {
|
|
||||||
if (context->container && context->container->selectedContainer)
|
|
||||||
context->container->selectedContainer->Command(context,
|
|
||||||
CONTAINER_LENGTH,
|
|
||||||
(const char *)length);
|
|
||||||
} else {
|
|
||||||
playback_err("not possible\n");
|
|
||||||
ret = cERR_PLAYBACK_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
playback_printf(20, "exiting with value %d\n", ret);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int PlaybackSwitchAudio(Player * context, int *pid)
|
bool Playback::SwitchVideo(int pid)
|
||||||
{
|
{
|
||||||
Track *track = context->manager.getAudioTrack(*pid);
|
Track *track = context->manager.getVideoTrack(pid);
|
||||||
if (track)
|
if (track)
|
||||||
context->container->selectedContainer->Command(context, CONTAINER_SWITCH_AUDIO, (const char*) track);
|
context->input.SwitchVideo(track);
|
||||||
return 0;
|
return !!track;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int PlaybackSwitchSubtitle(Player * context, int *pid)
|
bool Playback::SwitchAudio(int pid)
|
||||||
{
|
{
|
||||||
Track *track = context->manager.getSubtitleTrack(*pid);
|
Track *track = context->manager.getAudioTrack(pid);
|
||||||
if (track)
|
if (track)
|
||||||
context->container->selectedContainer->Command(context, CONTAINER_SWITCH_SUBTITLE, (const char*) track);
|
context->input.SwitchAudio(track);
|
||||||
return 0;
|
return !!track;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int PlaybackSwitchTeletext(Player * context, int *pid)
|
bool Playback::SwitchSubtitle(int pid)
|
||||||
{
|
{
|
||||||
Track *track = context->manager.getTeletextTrack(*pid);
|
Track *track = context->manager.getSubtitleTrack(pid);
|
||||||
if (track)
|
if (track)
|
||||||
context->container->selectedContainer->Command(context, CONTAINER_SWITCH_TELETEXT, (const char*) track);
|
context->input.SwitchSubtitle(track);
|
||||||
return 0;
|
return !!track;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int PlaybackMetadata(Player * context, char ***metadata)
|
bool Playback::SwitchTeletext(int pid)
|
||||||
{
|
{
|
||||||
int ret = cERR_PLAYBACK_NO_ERROR;
|
Track *track = context->manager.getTeletextTrack(pid);
|
||||||
|
if (track)
|
||||||
if (context->container && context->container->selectedContainer)
|
context->input.SwitchTeletext(track);
|
||||||
context->container->selectedContainer->Command(context,
|
return !!track;
|
||||||
CONTAINER_METADATA,
|
|
||||||
(const char *)metadata);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int Command(Player *context, PlaybackCmd_t command, void *argument)
|
bool Playback::GetMetadata(std::vector<std::string> &keys, std::vector<std::string> &values)
|
||||||
{
|
{
|
||||||
int ret = cERR_PLAYBACK_NO_ERROR;
|
return context->input.GetMetadata(keys, values);
|
||||||
|
|
||||||
playback_printf(20, "Command %d\n", command);
|
|
||||||
|
|
||||||
|
|
||||||
switch (command) {
|
|
||||||
case PLAYBACK_OPEN:{
|
|
||||||
ret = PlaybackOpen(context, (char *) argument);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PLAYBACK_CLOSE:{
|
|
||||||
ret = PlaybackClose(context);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PLAYBACK_PLAY:{
|
|
||||||
ret = PlaybackPlay(context);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PLAYBACK_STOP:{
|
|
||||||
ret = PlaybackStop(context);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PLAYBACK_PAUSE:{ // 4
|
|
||||||
ret = PlaybackPause(context);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PLAYBACK_CONTINUE:{
|
|
||||||
ret = PlaybackContinue(context);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PLAYBACK_TERM:{
|
|
||||||
ret = PlaybackTerminate(context);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PLAYBACK_FASTFORWARD:{
|
|
||||||
ret = PlaybackFastForward(context, (int *) argument);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PLAYBACK_SEEK:{
|
|
||||||
ret = PlaybackSeek(context, (float *) argument, 0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PLAYBACK_SEEK_ABS:{
|
|
||||||
ret = PlaybackSeek(context, (float *) argument, -1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PLAYBACK_PTS:{ // 10
|
|
||||||
ret = PlaybackPts(context, *((int64_t *) argument));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PLAYBACK_LENGTH:{ // 11
|
|
||||||
ret = PlaybackLength(context, (double *) argument);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PLAYBACK_SWITCH_AUDIO:{
|
|
||||||
ret = PlaybackSwitchAudio(context, (int *) argument);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PLAYBACK_SWITCH_SUBTITLE:{
|
|
||||||
ret = PlaybackSwitchSubtitle(context, (int *) argument);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PLAYBACK_METADATA:{
|
|
||||||
ret = PlaybackMetadata(context, (char ***) argument);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PLAYBACK_SLOWMOTION:{
|
|
||||||
ret = PlaybackSlowMotion(context, (int *) argument);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PLAYBACK_FASTBACKWARD:{
|
|
||||||
ret = PlaybackFastBackward(context, (int *) argument);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PLAYBACK_GET_FRAME_COUNT:{
|
|
||||||
// 10
|
|
||||||
ret = PlaybackGetFrameCount(context, *((int64_t *) argument));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PLAYBACK_SWITCH_TELETEXT:{
|
|
||||||
ret = PlaybackSwitchTeletext(context, (int *) argument);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
playback_err("PlaybackCmd %d not supported!\n", command);
|
|
||||||
ret = cERR_PLAYBACK_ERROR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
playback_printf(20, "exiting with value %d\n", ret);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Player::GetChapters(std::vector<int> &positions, std::vector<std::string> &titles)
|
||||||
|
{
|
||||||
|
positions.clear();
|
||||||
|
titles.clear();
|
||||||
|
input.UpdateTracks();
|
||||||
|
OpenThreads::ScopedLock<OpenThreads::Mutex> m_lock(chapterMutex);
|
||||||
|
for (std::vector<Chapter>::iterator it = chapters.begin(); it != chapters.end(); ++it) {
|
||||||
|
positions.push_back(1000 * it->start);
|
||||||
|
titles.push_back(it->title);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
PlaybackHandler_t PlaybackHandler = {
|
void Player::SetChapters(std::vector<Chapter> &Chapters)
|
||||||
"Playback",
|
{
|
||||||
-1,
|
OpenThreads::ScopedLock<OpenThreads::Mutex> m_lock(chapterMutex);
|
||||||
0,
|
chapters = Chapters;
|
||||||
0,
|
}
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
&Command,
|
|
||||||
"",
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
@@ -1,10 +0,0 @@
|
|||||||
#include "player.h"
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
Player::Player()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Player::~Player()
|
|
||||||
{
|
|
||||||
}
|
|
Reference in New Issue
Block a user