parent
d1fc67102a
commit
cae2adb75e
@ -0,0 +1,116 @@
|
|||||||
|
#include "demuxmedia.h"
|
||||||
|
|
||||||
|
DemuxMedia::DemuxMedia(QObject *parent, QQueue<MediaPacket *> *audioQueue,
|
||||||
|
QQueue<MediaPacket *> *videoQueue, void *channel, int stream_id) :
|
||||||
|
QObject(parent)
|
||||||
|
{
|
||||||
|
this->audioQueue = audioQueue;
|
||||||
|
this->videoQueue = videoQueue;
|
||||||
|
this->channel = channel;
|
||||||
|
this->stream_id = stream_id;
|
||||||
|
this->threadsStarted = false;
|
||||||
|
this->vcrFlag = 0;
|
||||||
|
|
||||||
|
playAudio = new PlayAudio(NULL, audioQueue, &sendMutex, channel, 101);
|
||||||
|
playAudioThread = new QThread(this);
|
||||||
|
connect(playAudioThread, SIGNAL(started()), playAudio, SLOT(play()));
|
||||||
|
playAudio->moveToThread(playAudioThread);
|
||||||
|
|
||||||
|
playVideo = new PlayVideo(NULL, videoQueue, &sendMutex, channel, 101);
|
||||||
|
playVideoThread = new QThread(this);
|
||||||
|
connect(playVideoThread, SIGNAL(started()), playVideo, SLOT(play()));
|
||||||
|
playVideo->moveToThread(playVideoThread);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DemuxMedia::setVcrOp(int op)
|
||||||
|
{
|
||||||
|
vcrMutex.lock();
|
||||||
|
vcrFlag = op;
|
||||||
|
vcrMutex.unlock();
|
||||||
|
|
||||||
|
if (playVideo)
|
||||||
|
playVideo->setVcrOp(op);
|
||||||
|
|
||||||
|
if (playAudio)
|
||||||
|
playAudio->setVcrOp(op);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DemuxMedia::startDemuxing()
|
||||||
|
{
|
||||||
|
MediaPacket *mediaPkt;
|
||||||
|
int is_video_frame;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
if ((audioQueue == NULL) || (videoQueue == NULL))
|
||||||
|
return;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
vcrMutex.lock();
|
||||||
|
switch (vcrFlag)
|
||||||
|
{
|
||||||
|
case VCR_PLAY:
|
||||||
|
vcrFlag = 0;
|
||||||
|
vcrMutex.unlock();
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VCR_PAUSE:
|
||||||
|
vcrMutex.unlock();
|
||||||
|
usleep(1000 * 100);
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VCR_STOP:
|
||||||
|
vcrMutex.unlock();
|
||||||
|
usleep(1000 * 100);
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
vcrMutex.unlock();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((audioQueue->count() >= 20) || (videoQueue->count() >= 20))
|
||||||
|
{
|
||||||
|
if (!threadsStarted)
|
||||||
|
startAudioVideoThreads();
|
||||||
|
|
||||||
|
usleep(1000 * 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
mediaPkt = new MediaPacket;
|
||||||
|
rv = xrdpvr_get_frame(&mediaPkt->av_pkt,
|
||||||
|
&is_video_frame,
|
||||||
|
&mediaPkt->delay_in_us);
|
||||||
|
if (rv < 0)
|
||||||
|
{
|
||||||
|
/* looks like we reached end of file */
|
||||||
|
delete mediaPkt;
|
||||||
|
usleep(1000 * 100);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_video_frame)
|
||||||
|
videoQueue->enqueue(mediaPkt);
|
||||||
|
else
|
||||||
|
audioQueue->enqueue(mediaPkt);
|
||||||
|
|
||||||
|
} /* end while (1) */
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayVideo * DemuxMedia::getPlayVideoInstance()
|
||||||
|
{
|
||||||
|
return this->playVideo;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DemuxMedia::startAudioVideoThreads()
|
||||||
|
{
|
||||||
|
if (threadsStarted)
|
||||||
|
return;
|
||||||
|
|
||||||
|
playVideoThread->start();
|
||||||
|
playAudioThread->start();
|
||||||
|
threadsStarted = true;
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
#ifndef DEMUXMEDIA_H
|
||||||
|
#define DEMUXMEDIA_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#define __STDC_CONSTANT_MACROS
|
||||||
|
#ifdef _STDINT_H
|
||||||
|
#undef _STDINT_H
|
||||||
|
#endif
|
||||||
|
#include <stdint.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QQueue>
|
||||||
|
#include <QThread>
|
||||||
|
#include <QMutex>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
#include "mediapacket.h"
|
||||||
|
#include "playaudio.h"
|
||||||
|
#include "playvideo.h"
|
||||||
|
|
||||||
|
/* ffmpeg related stuff */
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#include <libavformat/avformat.h>
|
||||||
|
#include <libavcodec/avcodec.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
#define VCR_PLAY 1
|
||||||
|
#define VCR_PAUSE 2
|
||||||
|
#define VCR_STOP 3
|
||||||
|
#define VCR_REWIND 4
|
||||||
|
#define VCR_POWER_OFF 5
|
||||||
|
|
||||||
|
class DemuxMedia : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit DemuxMedia(QObject *parent = 0, QQueue<MediaPacket *> *audioQueue = 0,
|
||||||
|
QQueue<MediaPacket *> *videoQueue = 0, void *channel = 0, int stream_id = 101);
|
||||||
|
|
||||||
|
void setVcrOp(int op);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void startDemuxing();
|
||||||
|
PlayVideo *getPlayVideoInstance();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QQueue<MediaPacket *> *audioQueue;
|
||||||
|
QQueue<MediaPacket *> *videoQueue;
|
||||||
|
QMutex vcrMutex;
|
||||||
|
int vcrFlag;
|
||||||
|
void *channel;
|
||||||
|
PlayVideo *playVideo;
|
||||||
|
QThread *playVideoThread;
|
||||||
|
PlayAudio *playAudio;
|
||||||
|
QThread *playAudioThread;
|
||||||
|
int stream_id;
|
||||||
|
bool threadsStarted;
|
||||||
|
QMutex sendMutex;
|
||||||
|
|
||||||
|
void startAudioVideoThreads();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DEMUXMEDIA_H
|
@ -0,0 +1,5 @@
|
|||||||
|
#include "mediapacket.h"
|
||||||
|
|
||||||
|
MediaPacket::MediaPacket()
|
||||||
|
{
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
#ifndef MEDIAPACKET_H
|
||||||
|
#define MEDIAPACKET_H
|
||||||
|
|
||||||
|
class MediaPacket
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MediaPacket();
|
||||||
|
|
||||||
|
void *av_pkt;
|
||||||
|
int delay_in_us;
|
||||||
|
int seq;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MEDIAPACKET_H
|
@ -0,0 +1,219 @@
|
|||||||
|
#include "ourinterface.h"
|
||||||
|
|
||||||
|
OurInterface::OurInterface(QObject *parent) :
|
||||||
|
QObject(parent)
|
||||||
|
{
|
||||||
|
channel = NULL;
|
||||||
|
savedGeometry.setX(0);
|
||||||
|
savedGeometry.setY(0);
|
||||||
|
savedGeometry.setWidth(0);
|
||||||
|
savedGeometry.setHeight(0);
|
||||||
|
stream_id = 101;
|
||||||
|
demuxMedia = 0;
|
||||||
|
//elapsedTime = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int OurInterface::oneTimeInit()
|
||||||
|
{
|
||||||
|
/* connect to remote client */
|
||||||
|
if (openVirtualChannel())
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* register all formats/codecs */
|
||||||
|
av_register_all();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OurInterface::oneTimeDeinit()
|
||||||
|
{
|
||||||
|
/* clean up resources */
|
||||||
|
closeVirtualChannel();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OurInterface::initRemoteClient()
|
||||||
|
{
|
||||||
|
int64_t start_time;
|
||||||
|
int64_t duration;
|
||||||
|
|
||||||
|
//elapsedTime = 0;
|
||||||
|
|
||||||
|
if (sendMetadataFile())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (sendVideoFormat())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (sendAudioFormat())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (sendGeometry(savedGeometry))
|
||||||
|
return;
|
||||||
|
|
||||||
|
xrdpvr_play_media(channel, 101, filename.toAscii().data());
|
||||||
|
|
||||||
|
xrdpvr_get_media_duration(&start_time, &duration);
|
||||||
|
qDebug() << "ourInterface:initRemoteClient: emit onMediaDurationInSecs: dur=" << duration;
|
||||||
|
emit onMediaDurationInSeconds(duration);
|
||||||
|
|
||||||
|
/* LK_TODO this needs to be undone in deinitRemoteClient() */
|
||||||
|
if (!demuxMedia)
|
||||||
|
{
|
||||||
|
demuxMedia = new DemuxMedia(NULL, &audioQueue, &videoQueue, channel, stream_id);
|
||||||
|
demuxMediaThread = new QThread(this);
|
||||||
|
connect(demuxMediaThread, SIGNAL(started()), demuxMedia, SLOT(startDemuxing()));
|
||||||
|
demuxMedia->moveToThread(demuxMediaThread);
|
||||||
|
playVideo = demuxMedia->getPlayVideoInstance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OurInterface::deInitRemoteClient()
|
||||||
|
{
|
||||||
|
/* perform clean up */
|
||||||
|
xrdpvr_deinit_player(channel, 101);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Open a virtual connection to remote client
|
||||||
|
*
|
||||||
|
* @return 0 on success, -1 on failure
|
||||||
|
******************************************************************************/
|
||||||
|
int OurInterface::openVirtualChannel()
|
||||||
|
{
|
||||||
|
/* is channel already open? */
|
||||||
|
if (channel)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* open a virtual channel and connect to remote client */
|
||||||
|
channel = WTSVirtualChannelOpenEx(WTS_CURRENT_SESSION, "xrdpvr", 0);
|
||||||
|
if (channel == NULL)
|
||||||
|
{
|
||||||
|
|
||||||
|
emit on_ErrorMsg("Connection failure",
|
||||||
|
"Error connecting to remote client. Application will close now");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int OurInterface::closeVirtualChannel()
|
||||||
|
{
|
||||||
|
/* channel must be opened first */
|
||||||
|
if (!channel)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
WTSVirtualChannelClose(channel);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief this is a temp hack while we figure out how to set up the right
|
||||||
|
* context for avcodec_decode_video2() on the server side; the workaround
|
||||||
|
* is to send the first 1MB of the media file to the server end which
|
||||||
|
* reads this file and sets up its context
|
||||||
|
*
|
||||||
|
* @return 0 on success, -1 on failure
|
||||||
|
******************************************************************************/
|
||||||
|
int OurInterface::sendMetadataFile()
|
||||||
|
{
|
||||||
|
if (xrdpvr_create_metadata_file(channel, filename.toAscii().data()))
|
||||||
|
{
|
||||||
|
emit on_ErrorMsg("I/O Error",
|
||||||
|
"An error occurred while sending data to remote client");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int OurInterface::sendVideoFormat()
|
||||||
|
{
|
||||||
|
if (xrdpvr_set_video_format(channel, stream_id))
|
||||||
|
{
|
||||||
|
emit on_ErrorMsg("I/O Error",
|
||||||
|
"Error sending video format to remote client");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int OurInterface::sendAudioFormat()
|
||||||
|
{
|
||||||
|
if (xrdpvr_set_audio_format(channel, stream_id))
|
||||||
|
{
|
||||||
|
emit on_ErrorMsg("I/O Error",
|
||||||
|
"Error sending audio format to remote client");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int OurInterface::sendGeometry(QRect rect)
|
||||||
|
{
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
savedGeometry.setX(rect.x());
|
||||||
|
savedGeometry.setY(rect.y());
|
||||||
|
savedGeometry.setWidth(rect.width());
|
||||||
|
savedGeometry.setHeight(rect.height());
|
||||||
|
|
||||||
|
rv = xrdpvr_set_geometry(channel, stream_id, savedGeometry.x(),
|
||||||
|
savedGeometry.y(), savedGeometry.width(),
|
||||||
|
savedGeometry.height());
|
||||||
|
|
||||||
|
if (rv)
|
||||||
|
{
|
||||||
|
emit on_ErrorMsg("I/O Error",
|
||||||
|
"Error sending screen geometry to remote client");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OurInterface::onGeometryChanged(int x, int y, int width, int height)
|
||||||
|
{
|
||||||
|
savedGeometry.setX(x);
|
||||||
|
savedGeometry.setY(y);
|
||||||
|
savedGeometry.setWidth(width);
|
||||||
|
savedGeometry.setHeight(height);
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
qDebug() << "OurInterface:signal" <<
|
||||||
|
"" << savedGeometry.x() <<
|
||||||
|
"" << savedGeometry.y() <<
|
||||||
|
"" << savedGeometry.width() <<
|
||||||
|
"" << savedGeometry.height();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
qDebug() << "setting geometry:channel=" << channel;
|
||||||
|
|
||||||
|
if (channel)
|
||||||
|
{
|
||||||
|
xrdpvr_set_geometry(channel, 101, savedGeometry.x(), savedGeometry.y(),
|
||||||
|
savedGeometry.width(), savedGeometry.height());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OurInterface::setFilename(QString filename)
|
||||||
|
{
|
||||||
|
this->filename = filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OurInterface::playMedia()
|
||||||
|
{
|
||||||
|
demuxMediaThread->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayVideo * OurInterface::getPlayVideoInstance()
|
||||||
|
{
|
||||||
|
return this->playVideo;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OurInterface::setVcrOp(int op)
|
||||||
|
{
|
||||||
|
if (demuxMedia)
|
||||||
|
demuxMedia->setVcrOp(op);
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
#ifndef OURINTERFACE_H
|
||||||
|
#define OURINTERFACE_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#define __STDC_CONSTANT_MACROS
|
||||||
|
#ifdef _STDINT_H
|
||||||
|
#undef _STDINT_H
|
||||||
|
#endif
|
||||||
|
#include <stdint.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QRect>
|
||||||
|
#include <QDebug> // LK_TODO
|
||||||
|
|
||||||
|
#include "xrdpvr.h"
|
||||||
|
#include "xrdpapi.h"
|
||||||
|
#include "demuxmedia.h"
|
||||||
|
#include "playvideo.h"
|
||||||
|
|
||||||
|
/* ffmpeg related stuff */
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#include <libavformat/avformat.h>
|
||||||
|
#include <libavcodec/avcodec.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
class OurInterface : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit OurInterface(QObject *parent = 0);
|
||||||
|
|
||||||
|
/* public methods */
|
||||||
|
int oneTimeInit();
|
||||||
|
void oneTimeDeinit();
|
||||||
|
void initRemoteClient();
|
||||||
|
void deInitRemoteClient();
|
||||||
|
int sendGeometry(QRect rect);
|
||||||
|
void setFilename(QString filename);
|
||||||
|
void playMedia();
|
||||||
|
PlayVideo *getPlayVideoInstance();
|
||||||
|
void setVcrOp(int op);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void onGeometryChanged(int x, int y, int width, int height);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void on_ErrorMsg(QString title, QString msg);
|
||||||
|
void onMediaDurationInSeconds(int duration);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/* private stuff */
|
||||||
|
QQueue<MediaPacket *> audioQueue;
|
||||||
|
QQueue<MediaPacket *> videoQueue;
|
||||||
|
|
||||||
|
DemuxMedia *demuxMedia;
|
||||||
|
QThread *demuxMediaThread;
|
||||||
|
PlayVideo *playVideo;
|
||||||
|
QString filename;
|
||||||
|
void *channel;
|
||||||
|
int stream_id;
|
||||||
|
QRect savedGeometry;
|
||||||
|
|
||||||
|
/* private methods */
|
||||||
|
int openVirtualChannel();
|
||||||
|
int closeVirtualChannel();
|
||||||
|
int sendMetadataFile();
|
||||||
|
int sendVideoFormat();
|
||||||
|
int sendAudioFormat();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // INTERFACE_H
|
@ -0,0 +1,87 @@
|
|||||||
|
#include "playaudio.h"
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
PlayAudio::PlayAudio(QObject *parent,
|
||||||
|
QQueue<MediaPacket *> *audioQueue,
|
||||||
|
QMutex *sendMutex,
|
||||||
|
void *channel,
|
||||||
|
int stream_id) :
|
||||||
|
QObject(parent)
|
||||||
|
{
|
||||||
|
this->audioQueue = audioQueue;
|
||||||
|
this->sendMutex = sendMutex;
|
||||||
|
this->channel = channel;
|
||||||
|
this->stream_id = stream_id;
|
||||||
|
this->vcrFlag = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayAudio::play()
|
||||||
|
{
|
||||||
|
MediaPacket *pkt;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
vcrMutex.lock();
|
||||||
|
switch (vcrFlag)
|
||||||
|
{
|
||||||
|
case VCR_PLAY:
|
||||||
|
vcrFlag = 0;
|
||||||
|
vcrMutex.unlock();
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VCR_PAUSE:
|
||||||
|
vcrMutex.unlock();
|
||||||
|
usleep(1000 * 100);
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VCR_STOP:
|
||||||
|
vcrMutex.unlock();
|
||||||
|
clearAudioQ();
|
||||||
|
usleep(1000 * 100);
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
vcrMutex.unlock();
|
||||||
|
goto label1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
label1:
|
||||||
|
|
||||||
|
if (audioQueue->isEmpty())
|
||||||
|
{
|
||||||
|
qDebug() << "PlayAudio::play: GOT EMPTY";
|
||||||
|
usleep(1000 * 100);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
pkt = audioQueue->dequeue();
|
||||||
|
sendMutex->lock();
|
||||||
|
send_audio_pkt(channel, stream_id, pkt->av_pkt);
|
||||||
|
sendMutex->unlock();
|
||||||
|
delete pkt;
|
||||||
|
usleep(pkt->delay_in_us);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayAudio::setVcrOp(int op)
|
||||||
|
{
|
||||||
|
vcrMutex.lock();
|
||||||
|
this->vcrFlag = op;
|
||||||
|
vcrMutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayAudio::clearAudioQ()
|
||||||
|
{
|
||||||
|
MediaPacket *pkt;
|
||||||
|
|
||||||
|
while (!audioQueue->isEmpty())
|
||||||
|
{
|
||||||
|
pkt = audioQueue->dequeue();
|
||||||
|
av_free_packet((AVPacket *) pkt->av_pkt);
|
||||||
|
delete pkt;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
#ifndef PLAYAUDIO_H
|
||||||
|
#define PLAYAUDIO_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#define __STDC_CONSTANT_MACROS
|
||||||
|
#ifdef _STDINT_H
|
||||||
|
#undef _STDINT_H
|
||||||
|
#endif
|
||||||
|
#include <stdint.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QQueue>
|
||||||
|
#include <QMutex>
|
||||||
|
|
||||||
|
#include "mediapacket.h"
|
||||||
|
#include "xrdpvr.h"
|
||||||
|
|
||||||
|
/* ffmpeg related stuff */
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#include <libavformat/avformat.h>
|
||||||
|
#include <libavcodec/avcodec.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
#define VCR_PLAY 1
|
||||||
|
#define VCR_PAUSE 2
|
||||||
|
#define VCR_STOP 3
|
||||||
|
#define VCR_REWIND 4
|
||||||
|
#define VCR_POWER_OFF 5
|
||||||
|
|
||||||
|
class PlayAudio : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit PlayAudio(QObject *parent = 0,
|
||||||
|
QQueue<MediaPacket *> *audioQueue = 0,
|
||||||
|
QMutex *sendMutex = 0,
|
||||||
|
void *channel = 0,
|
||||||
|
int stream_id = 101);
|
||||||
|
|
||||||
|
void setVcrOp(int op);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void play();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QQueue<MediaPacket *> *audioQueue;
|
||||||
|
QMutex *sendMutex;
|
||||||
|
QMutex vcrMutex;
|
||||||
|
int vcrFlag;
|
||||||
|
void *channel;
|
||||||
|
int stream_id;
|
||||||
|
|
||||||
|
void clearAudioQ();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // PLAYAUDIO_H
|
@ -0,0 +1,173 @@
|
|||||||
|
#include "playvideo.h"
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
PlayVideo::PlayVideo(QObject *parent,
|
||||||
|
QQueue<MediaPacket *> *videoQueue,
|
||||||
|
QMutex *sendMutex,
|
||||||
|
void *channel,
|
||||||
|
int stream_id) :
|
||||||
|
QObject(parent)
|
||||||
|
{
|
||||||
|
this->videoQueue = videoQueue;
|
||||||
|
this->channel = channel;
|
||||||
|
this->sendMutex = sendMutex;
|
||||||
|
this->stream_id = stream_id;
|
||||||
|
elapsedTime = 0;
|
||||||
|
pausedTime = 0;
|
||||||
|
la_seekPos = -1;
|
||||||
|
vcrFlag = 0;
|
||||||
|
isStopped = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayVideo::play()
|
||||||
|
{
|
||||||
|
MediaPacket *pkt;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
vcrMutex.lock();
|
||||||
|
switch (vcrFlag)
|
||||||
|
{
|
||||||
|
case VCR_PLAY:
|
||||||
|
vcrFlag = 0;
|
||||||
|
vcrMutex.unlock();
|
||||||
|
if (pausedTime)
|
||||||
|
{
|
||||||
|
elapsedTime = av_gettime() - pausedTime;
|
||||||
|
pausedTime = 0;
|
||||||
|
}
|
||||||
|
isStopped = false;
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VCR_PAUSE:
|
||||||
|
vcrMutex.unlock();
|
||||||
|
if (!pausedTime)
|
||||||
|
{
|
||||||
|
/* save amount of video played so far */
|
||||||
|
pausedTime = av_gettime() - elapsedTime;
|
||||||
|
}
|
||||||
|
usleep(1000 * 100);
|
||||||
|
isStopped = false;
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VCR_STOP:
|
||||||
|
vcrMutex.unlock();
|
||||||
|
if (isStopped)
|
||||||
|
{
|
||||||
|
usleep(1000 * 100);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
clearVideoQ();
|
||||||
|
elapsedTime = 0;
|
||||||
|
pausedTime = 0;
|
||||||
|
la_seekPos = -1;
|
||||||
|
xrdpvr_seek_media(0, 0);
|
||||||
|
isStopped = true;
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
vcrMutex.unlock();
|
||||||
|
goto label1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
label1:
|
||||||
|
|
||||||
|
if (videoQueue->isEmpty())
|
||||||
|
{
|
||||||
|
qDebug() << "PlayVideo::play: GOT EMPTY";
|
||||||
|
usleep(1000 * 100);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
pkt = videoQueue->dequeue();
|
||||||
|
sendMutex->lock();
|
||||||
|
send_video_pkt(channel, stream_id, pkt->av_pkt);
|
||||||
|
sendMutex->unlock();
|
||||||
|
delete pkt;
|
||||||
|
usleep(pkt->delay_in_us);
|
||||||
|
|
||||||
|
updateMediaPos();
|
||||||
|
|
||||||
|
if (elapsedTime == 0)
|
||||||
|
elapsedTime = av_gettime();
|
||||||
|
|
||||||
|
/* time elapsed in 1/100th sec units since play started */
|
||||||
|
emit onElapsedtime((av_gettime() - elapsedTime) / 10000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayVideo::onMediaSeek(int value)
|
||||||
|
{
|
||||||
|
posMutex.lock();
|
||||||
|
la_seekPos = value;
|
||||||
|
posMutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayVideo::updateMediaPos()
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
if (elapsedTime == 0)
|
||||||
|
elapsedTime = av_gettime();
|
||||||
|
|
||||||
|
/* time elapsed in 1/100th sec units since play started */
|
||||||
|
emit onElapsedtime((av_gettime() - elapsedTime) / 10000);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
posMutex.lock();
|
||||||
|
if (la_seekPos >= 0)
|
||||||
|
{
|
||||||
|
qDebug() << "seeking to" << la_seekPos;
|
||||||
|
xrdpvr_seek_media(la_seekPos, 0);
|
||||||
|
elapsedTime = av_gettime() - la_seekPos * 1000000;
|
||||||
|
la_seekPos = -1;
|
||||||
|
}
|
||||||
|
posMutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayVideo::setVcrOp(int op)
|
||||||
|
{
|
||||||
|
vcrMutex.lock();
|
||||||
|
this->vcrFlag = op;
|
||||||
|
vcrMutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayVideo::clearVideoQ()
|
||||||
|
{
|
||||||
|
MediaPacket *pkt;
|
||||||
|
|
||||||
|
while (!videoQueue->isEmpty())
|
||||||
|
{
|
||||||
|
pkt = videoQueue->dequeue();
|
||||||
|
av_free_packet((AVPacket *) pkt->av_pkt);
|
||||||
|
delete pkt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
void DecoderThread::updateSlider()
|
||||||
|
{
|
||||||
|
if (elapsedTime == 0)
|
||||||
|
elapsedTime = av_gettime();
|
||||||
|
|
||||||
|
/* time elapsed in 1/100th sec units since play started */
|
||||||
|
emit onElapsedtime((av_gettime() - elapsedTime) / 10000);
|
||||||
|
|
||||||
|
mutex.lock();
|
||||||
|
if (la_seekPos >= 0)
|
||||||
|
{
|
||||||
|
qDebug() << "seeking to" << la_seekPos;
|
||||||
|
//audioTimer->stop();
|
||||||
|
//videoTimer->stop();
|
||||||
|
xrdpvr_seek_media(la_seekPos, 0);
|
||||||
|
elapsedTime = av_gettime() - la_seekPos * 1000000;
|
||||||
|
//audioTimer->start(10);
|
||||||
|
//videoTimer->start(10);
|
||||||
|
la_seekPos = -1;
|
||||||
|
}
|
||||||
|
mutex.unlock();
|
||||||
|
}
|
||||||
|
#endif
|
@ -0,0 +1,71 @@
|
|||||||
|
#ifndef PLAYVIDEO_H
|
||||||
|
#define PLAYVIDEO_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#define __STDC_CONSTANT_MACROS
|
||||||
|
#ifdef _STDINT_H
|
||||||
|
#undef _STDINT_H
|
||||||
|
#endif
|
||||||
|
#include <stdint.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QQueue>
|
||||||
|
#include <QMutex>
|
||||||
|
|
||||||
|
#include "mediapacket.h"
|
||||||
|
#include "xrdpvr.h"
|
||||||
|
#include "xrdpapi.h"
|
||||||
|
|
||||||
|
/* ffmpeg related stuff */
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#include <libavformat/avformat.h>
|
||||||
|
#include <libavcodec/avcodec.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
#define VCR_PLAY 1
|
||||||
|
#define VCR_PAUSE 2
|
||||||
|
#define VCR_STOP 3
|
||||||
|
#define VCR_REWIND 4
|
||||||
|
#define VCR_POWER_OFF 5
|
||||||
|
|
||||||
|
class PlayVideo : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit PlayVideo(QObject *parent = 0,
|
||||||
|
QQueue<MediaPacket *> *videoQueue = 0,
|
||||||
|
QMutex *sendMutex = 0,
|
||||||
|
void *channel = 0,
|
||||||
|
int stream_id = 101);
|
||||||
|
|
||||||
|
void onMediaSeek(int value);
|
||||||
|
void setVcrOp(int op);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void play();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void onElapsedtime(int val); /* in hundredth of a sec */
|
||||||
|
|
||||||
|
private:
|
||||||
|
QQueue<MediaPacket *> *videoQueue;
|
||||||
|
|
||||||
|
int vcrFlag;
|
||||||
|
QMutex vcrMutex;
|
||||||
|
QMutex *sendMutex;
|
||||||
|
QMutex posMutex;
|
||||||
|
int64_t la_seekPos; /* locked access; must hold posMutex */
|
||||||
|
void *channel;
|
||||||
|
int stream_id;
|
||||||
|
int64_t elapsedTime; /* elapsed time in usecs since play started */
|
||||||
|
int64_t pausedTime; /* time at which stream was paused */
|
||||||
|
bool isStopped;
|
||||||
|
|
||||||
|
void updateMediaPos();
|
||||||
|
void clearVideoQ();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // PLAYVIDEO_H
|
Loading…
Reference in new issue