extract memory buffer from HLS mediasubsession
parent
fbdc2bc710
commit
7cd878c6db
@ -0,0 +1,71 @@
|
||||
/* ---------------------------------------------------------------------------
|
||||
** This software is in the public domain, furnished "as is", without technical
|
||||
** support, and with no warranty, express or implied, as to its usefulness for
|
||||
** any purpose.
|
||||
**
|
||||
** AddH26xMarkerFilter.h
|
||||
**
|
||||
** -------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
class AddH26xMarkerFilter : public FramedFilter {
|
||||
public:
|
||||
AddH26xMarkerFilter (UsageEnvironment& env, FramedSource* inputSource): FramedFilter(env, inputSource) {
|
||||
m_bufferSize = OutPacketBuffer::maxSize;
|
||||
m_buffer = new unsigned char[m_bufferSize];
|
||||
}
|
||||
virtual ~AddH26xMarkerFilter () {
|
||||
delete [] m_buffer;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
static void afterGettingFrame(void* clientData, unsigned frameSize,
|
||||
unsigned numTruncatedBytes,
|
||||
struct timeval presentationTime,
|
||||
unsigned durationInMicroseconds) {
|
||||
AddH26xMarkerFilter* sink = (AddH26xMarkerFilter*)clientData;
|
||||
sink->afterGettingFrame(frameSize, numTruncatedBytes, presentationTime);
|
||||
}
|
||||
|
||||
void afterGettingFrame(unsigned frameSize, unsigned numTruncatedBytes, struct timeval presentationTime)
|
||||
{
|
||||
fPresentationTime = presentationTime;
|
||||
fDurationInMicroseconds = 0;
|
||||
if (numTruncatedBytes > 0)
|
||||
{
|
||||
envir() << "AddH26xMarkerFilter::afterGettingFrame(): The input frame data was too large for our buffer size truncated:" << numTruncatedBytes << " bufferSize:" << m_bufferSize << "\n";
|
||||
m_bufferSize += numTruncatedBytes;
|
||||
delete[] m_buffer;
|
||||
m_buffer = new unsigned char[m_bufferSize];
|
||||
fFrameSize = 0;
|
||||
} else {
|
||||
char marker[] = {0,0,0,1};
|
||||
fFrameSize = frameSize + sizeof(marker);
|
||||
if (fFrameSize > fMaxSize) {
|
||||
fNumTruncatedBytes = fFrameSize - fMaxSize;
|
||||
envir() << "AddH26xMarkerFilter::afterGettingFrame(): buffer too small truncated:" << fNumTruncatedBytes << " bufferSize:" << fFrameSize << "\n";
|
||||
} else {
|
||||
fNumTruncatedBytes = 0;
|
||||
memcpy(fTo, marker, sizeof(marker));
|
||||
memcpy(fTo+sizeof(marker), m_buffer, frameSize);
|
||||
}
|
||||
}
|
||||
afterGetting(this);
|
||||
}
|
||||
|
||||
virtual void doGetNextFrame() {
|
||||
if (fInputSource != NULL)
|
||||
{
|
||||
fInputSource->getNextFrame(m_buffer, m_bufferSize,
|
||||
afterGettingFrame, this,
|
||||
handleClosure, this);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char* m_buffer;
|
||||
unsigned int m_bufferSize;
|
||||
};
|
||||
|
||||
|
@ -0,0 +1,56 @@
|
||||
/* ---------------------------------------------------------------------------
|
||||
** This software is in the public domain, furnished "as is", without technical
|
||||
** support, and with no warranty, express or implied, as to its usefulness for
|
||||
** any purpose.
|
||||
**
|
||||
** MemoryBufferSink.h
|
||||
**
|
||||
** Implement a live555 Sink that store time slices in memory
|
||||
**
|
||||
** -------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "MediaSink.hh"
|
||||
|
||||
class MemoryBufferSink : public MediaSink
|
||||
{
|
||||
public:
|
||||
static MemoryBufferSink* createNew(UsageEnvironment& env, unsigned int bufferSize, unsigned int sliceDuration)
|
||||
{
|
||||
return new MemoryBufferSink(env, bufferSize, sliceDuration);
|
||||
}
|
||||
|
||||
protected:
|
||||
MemoryBufferSink(UsageEnvironment& env, unsigned bufferSize, unsigned int sliceDuration);
|
||||
virtual ~MemoryBufferSink();
|
||||
|
||||
virtual Boolean continuePlaying();
|
||||
|
||||
static void afterGettingFrame(void* clientData, unsigned frameSize,
|
||||
unsigned numTruncatedBytes,
|
||||
struct timeval presentationTime,
|
||||
unsigned durationInMicroseconds) {
|
||||
MemoryBufferSink* sink = (MemoryBufferSink*)clientData;
|
||||
sink->afterGettingFrame(frameSize, numTruncatedBytes, presentationTime);
|
||||
}
|
||||
|
||||
void afterGettingFrame(unsigned frameSize, unsigned numTruncatedBytes, struct timeval presentationTime);
|
||||
|
||||
public:
|
||||
unsigned int getBufferSize(unsigned int slice);
|
||||
std::string getBuffer(unsigned int slice);
|
||||
unsigned int firstTime();
|
||||
unsigned int duration();
|
||||
unsigned int getSliceDuration() { return m_sliceDuration; }
|
||||
|
||||
private:
|
||||
unsigned char * m_buffer;
|
||||
unsigned int m_bufferSize;
|
||||
std::map<unsigned int,std::string> m_outputBuffers;
|
||||
unsigned int m_refTime;
|
||||
unsigned int m_sliceDuration;
|
||||
};
|
||||
|
@ -1,79 +0,0 @@
|
||||
/* ---------------------------------------------------------------------------
|
||||
** This software is in the public domain, furnished "as is", without technical
|
||||
** support, and with no warranty, express or implied, as to its usefulness for
|
||||
** any purpose.
|
||||
**
|
||||
** ServerMediaSubsession.h
|
||||
**
|
||||
** -------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include "UnicastServerMediaSubsession.h"
|
||||
|
||||
// -----------------------------------------
|
||||
// ServerMediaSubsession for HLS
|
||||
// -----------------------------------------
|
||||
class HLSServerMediaSubsession : public UnicastServerMediaSubsession
|
||||
{
|
||||
class HLSSink : public MediaSink
|
||||
{
|
||||
public:
|
||||
static HLSSink* createNew(UsageEnvironment& env, unsigned int bufferSize, unsigned int sliceDuration)
|
||||
{
|
||||
return new HLSSink(env, bufferSize, sliceDuration);
|
||||
}
|
||||
|
||||
protected:
|
||||
HLSSink(UsageEnvironment& env, unsigned bufferSize, unsigned int sliceDuration);
|
||||
virtual ~HLSSink();
|
||||
|
||||
virtual Boolean continuePlaying();
|
||||
|
||||
static void afterGettingFrame(void* clientData, unsigned frameSize,
|
||||
unsigned numTruncatedBytes,
|
||||
struct timeval presentationTime,
|
||||
unsigned durationInMicroseconds) {
|
||||
HLSSink* sink = (HLSSink*)clientData;
|
||||
sink->afterGettingFrame(frameSize, numTruncatedBytes, presentationTime);
|
||||
}
|
||||
|
||||
void afterGettingFrame(unsigned frameSize, unsigned numTruncatedBytes, struct timeval presentationTime);
|
||||
|
||||
public:
|
||||
unsigned int getHLSBufferSize(unsigned int slice);
|
||||
std::string getHLSBuffer(unsigned int slice);
|
||||
unsigned int firstTime();
|
||||
unsigned int duration();
|
||||
unsigned int getSliceDuration() { return m_sliceDuration; }
|
||||
|
||||
private:
|
||||
unsigned char * m_buffer;
|
||||
unsigned int m_bufferSize;
|
||||
std::map<unsigned int,std::string> m_outputBuffers;
|
||||
unsigned int m_refTime;
|
||||
unsigned int m_sliceDuration;
|
||||
};
|
||||
|
||||
public:
|
||||
static HLSServerMediaSubsession* createNew(UsageEnvironment& env, StreamReplicator* replicator, const std::string& format, unsigned int sliceDuration)
|
||||
{
|
||||
return new HLSServerMediaSubsession(env, replicator, format, sliceDuration);
|
||||
}
|
||||
|
||||
protected:
|
||||
HLSServerMediaSubsession(UsageEnvironment& env, StreamReplicator* replicator, const std::string& format, unsigned int sliceDuration);
|
||||
virtual ~HLSServerMediaSubsession();
|
||||
|
||||
virtual float getCurrentNPT(void* streamToken);
|
||||
virtual float duration() const ;
|
||||
virtual void seekStream(unsigned clientSessionId, void* streamToken, double& seekNPT, double streamDuration, u_int64_t& numBytes);
|
||||
virtual FramedSource* getStreamSource(void* streamToken);
|
||||
|
||||
protected:
|
||||
unsigned int m_slice;
|
||||
HLSSink * m_hlsSink;
|
||||
};
|
||||
|
||||
|
@ -0,0 +1,41 @@
|
||||
/* ---------------------------------------------------------------------------
|
||||
** This software is in the public domain, furnished "as is", without technical
|
||||
** support, and with no warranty, express or implied, as to its usefulness for
|
||||
** any purpose.
|
||||
**
|
||||
** TSServerMediaSubsession.h
|
||||
**
|
||||
** -------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include "UnicastServerMediaSubsession.h"
|
||||
#include "MemoryBufferSink.h"
|
||||
|
||||
// -----------------------------------------
|
||||
// ServerMediaSubsession for HLS
|
||||
// -----------------------------------------
|
||||
class TSServerMediaSubsession : public UnicastServerMediaSubsession
|
||||
{
|
||||
public:
|
||||
static TSServerMediaSubsession* createNew(UsageEnvironment& env, StreamReplicator* replicator, const std::string& format, unsigned int sliceDuration)
|
||||
{
|
||||
return new TSServerMediaSubsession(env, replicator, format, sliceDuration);
|
||||
}
|
||||
|
||||
protected:
|
||||
TSServerMediaSubsession(UsageEnvironment& env, StreamReplicator* replicator, const std::string& format, unsigned int sliceDuration);
|
||||
virtual ~TSServerMediaSubsession();
|
||||
|
||||
virtual float getCurrentNPT(void* streamToken);
|
||||
virtual float duration() const ;
|
||||
virtual void seekStream(unsigned clientSessionId, void* streamToken, double& seekNPT, double streamDuration, u_int64_t& numBytes);
|
||||
virtual FramedSource* getStreamSource(void* streamToken);
|
||||
|
||||
protected:
|
||||
unsigned int m_slice;
|
||||
MemoryBufferSink* m_hlsSink;
|
||||
};
|
||||
|
||||
|
@ -0,0 +1,112 @@
|
||||
/* ---------------------------------------------------------------------------
|
||||
** This software is in the public domain, furnished "as is", without technical
|
||||
** support, and with no warranty, express or implied, as to its usefulness for
|
||||
** any purpose.
|
||||
**
|
||||
** MemoryBufferSink.cpp
|
||||
**
|
||||
** -------------------------------------------------------------------------*/
|
||||
|
||||
#include "MemoryBufferSink.h"
|
||||
|
||||
// -----------------------------------------
|
||||
// MemoryBufferSink
|
||||
// -----------------------------------------
|
||||
MemoryBufferSink::MemoryBufferSink(UsageEnvironment& env, unsigned bufferSize, unsigned int sliceDuration) : MediaSink(env), m_bufferSize(bufferSize), m_refTime(0), m_sliceDuration(sliceDuration)
|
||||
{
|
||||
m_buffer = new unsigned char[m_bufferSize];
|
||||
}
|
||||
|
||||
MemoryBufferSink::~MemoryBufferSink()
|
||||
{
|
||||
delete[] m_buffer;
|
||||
}
|
||||
|
||||
|
||||
Boolean MemoryBufferSink::continuePlaying()
|
||||
{
|
||||
Boolean ret = False;
|
||||
if (fSource != NULL)
|
||||
{
|
||||
fSource->getNextFrame(m_buffer, m_bufferSize,
|
||||
afterGettingFrame, this,
|
||||
onSourceClosure, this);
|
||||
ret = True;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void MemoryBufferSink::afterGettingFrame(unsigned frameSize, unsigned numTruncatedBytes, struct timeval presentationTime)
|
||||
{
|
||||
if (numTruncatedBytes > 0)
|
||||
{
|
||||
envir() << "FileSink::afterGettingFrame(): The input frame data was too large for our buffer size \n";
|
||||
// realloc a bigger buffer
|
||||
m_bufferSize += numTruncatedBytes;
|
||||
delete[] m_buffer;
|
||||
m_buffer = new unsigned char[m_bufferSize];
|
||||
}
|
||||
else
|
||||
{
|
||||
// append buffer to slice buffer
|
||||
if (m_refTime == 0)
|
||||
{
|
||||
m_refTime = presentationTime.tv_sec;
|
||||
}
|
||||
unsigned int slice = (presentationTime.tv_sec-m_refTime)/m_sliceDuration;
|
||||
std::string& outputBuffer = m_outputBuffers[slice];
|
||||
outputBuffer.append((const char*)m_buffer, frameSize);
|
||||
|
||||
// remove old buffers
|
||||
while (m_outputBuffers.size()>5)
|
||||
{
|
||||
m_outputBuffers.erase(m_outputBuffers.begin());
|
||||
}
|
||||
}
|
||||
|
||||
continuePlaying();
|
||||
}
|
||||
|
||||
unsigned int MemoryBufferSink::getBufferSize(unsigned int slice)
|
||||
{
|
||||
unsigned int size = 0;
|
||||
std::map<unsigned int,std::string>::iterator it = m_outputBuffers.find(slice);
|
||||
if (it != m_outputBuffers.end())
|
||||
{
|
||||
size = it->second.size();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
std::string MemoryBufferSink::getBuffer(unsigned int slice)
|
||||
{
|
||||
std::string content;
|
||||
std::map<unsigned int,std::string>::iterator it = m_outputBuffers.find(slice);
|
||||
if (it != m_outputBuffers.end())
|
||||
{
|
||||
content = it->second;
|
||||
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
unsigned int MemoryBufferSink::firstTime()
|
||||
{
|
||||
unsigned int firstTime = 0;
|
||||
if (m_outputBuffers.size() != 0)
|
||||
{
|
||||
firstTime = m_outputBuffers.begin()->first;
|
||||
}
|
||||
return firstTime*m_sliceDuration;
|
||||
}
|
||||
|
||||
unsigned int MemoryBufferSink::duration()
|
||||
{
|
||||
unsigned int duration = 0;
|
||||
if (m_outputBuffers.size() != 0)
|
||||
{
|
||||
duration = m_outputBuffers.rbegin()->first - m_outputBuffers.begin()->first;
|
||||
}
|
||||
return (duration)*m_sliceDuration;
|
||||
}
|
@ -1,241 +0,0 @@
|
||||
/* ---------------------------------------------------------------------------
|
||||
** This software is in the public domain, furnished "as is", without technical
|
||||
** support, and with no warranty, express or implied, as to its usefulness for
|
||||
** any purpose.
|
||||
**
|
||||
** SegmentServerMediaSubsession.cpp
|
||||
**
|
||||
** -------------------------------------------------------------------------*/
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "SegmentServerMediaSubsession.h"
|
||||
|
||||
// -----------------------------------------
|
||||
// ServerMediaSubsession for HLS
|
||||
// -----------------------------------------
|
||||
HLSServerMediaSubsession::HLSSink::HLSSink(UsageEnvironment& env, unsigned bufferSize, unsigned int sliceDuration) : MediaSink(env), m_bufferSize(bufferSize), m_refTime(0), m_sliceDuration(sliceDuration)
|
||||
{
|
||||
m_buffer = new unsigned char[m_bufferSize];
|
||||
}
|
||||
|
||||
HLSServerMediaSubsession::HLSSink::~HLSSink()
|
||||
{
|
||||
delete[] m_buffer;
|
||||
}
|
||||
|
||||
|
||||
Boolean HLSServerMediaSubsession::HLSSink::continuePlaying()
|
||||
{
|
||||
Boolean ret = False;
|
||||
if (fSource != NULL)
|
||||
{
|
||||
fSource->getNextFrame(m_buffer, m_bufferSize,
|
||||
afterGettingFrame, this,
|
||||
onSourceClosure, this);
|
||||
ret = True;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void HLSServerMediaSubsession::HLSSink::afterGettingFrame(unsigned frameSize, unsigned numTruncatedBytes, struct timeval presentationTime)
|
||||
{
|
||||
if (numTruncatedBytes > 0)
|
||||
{
|
||||
envir() << "FileSink::afterGettingFrame(): The input frame data was too large for our buffer size \n";
|
||||
// realloc a bigger buffer
|
||||
m_bufferSize += numTruncatedBytes;
|
||||
delete[] m_buffer;
|
||||
m_buffer = new unsigned char[m_bufferSize];
|
||||
}
|
||||
else
|
||||
{
|
||||
// append buffer to slice buffer
|
||||
if (m_refTime == 0)
|
||||
{
|
||||
m_refTime = presentationTime.tv_sec;
|
||||
}
|
||||
unsigned int slice = (presentationTime.tv_sec-m_refTime)/m_sliceDuration;
|
||||
std::string& outputBuffer = m_outputBuffers[slice];
|
||||
outputBuffer.append((const char*)m_buffer, frameSize);
|
||||
|
||||
// remove old buffers
|
||||
while (m_outputBuffers.size()>5)
|
||||
{
|
||||
m_outputBuffers.erase(m_outputBuffers.begin());
|
||||
}
|
||||
}
|
||||
|
||||
continuePlaying();
|
||||
}
|
||||
|
||||
unsigned int HLSServerMediaSubsession::HLSSink::getHLSBufferSize(unsigned int slice)
|
||||
{
|
||||
unsigned int size = 0;
|
||||
std::map<unsigned int,std::string>::iterator it = m_outputBuffers.find(slice);
|
||||
if (it != m_outputBuffers.end())
|
||||
{
|
||||
size = it->second.size();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
std::string HLSServerMediaSubsession::HLSSink::getHLSBuffer(unsigned int slice)
|
||||
{
|
||||
std::string content;
|
||||
std::map<unsigned int,std::string>::iterator it = m_outputBuffers.find(slice);
|
||||
if (it != m_outputBuffers.end())
|
||||
{
|
||||
content = it->second;
|
||||
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
unsigned int HLSServerMediaSubsession::HLSSink::firstTime()
|
||||
{
|
||||
unsigned int firstTime = 0;
|
||||
if (m_outputBuffers.size() != 0)
|
||||
{
|
||||
firstTime = m_outputBuffers.begin()->first;
|
||||
}
|
||||
return firstTime*m_sliceDuration;
|
||||
}
|
||||
|
||||
unsigned int HLSServerMediaSubsession::HLSSink::duration()
|
||||
{
|
||||
unsigned int duration = 0;
|
||||
if (m_outputBuffers.size() != 0)
|
||||
{
|
||||
duration = m_outputBuffers.rbegin()->first - m_outputBuffers.begin()->first;
|
||||
}
|
||||
return (duration)*m_sliceDuration;
|
||||
}
|
||||
|
||||
char marker[] = {0,0,0,1};
|
||||
class AddMarker : public FramedFilter {
|
||||
public:
|
||||
AddMarker (UsageEnvironment& env, FramedSource* inputSource): FramedFilter(env, inputSource) {
|
||||
m_bufferSize = OutPacketBuffer::maxSize;
|
||||
m_buffer = new unsigned char[m_bufferSize];
|
||||
}
|
||||
virtual ~AddMarker () {
|
||||
delete [] m_buffer;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
static void afterGettingFrame(void* clientData, unsigned frameSize,
|
||||
unsigned numTruncatedBytes,
|
||||
struct timeval presentationTime,
|
||||
unsigned durationInMicroseconds) {
|
||||
AddMarker* sink = (AddMarker*)clientData;
|
||||
sink->afterGettingFrame(frameSize, numTruncatedBytes, presentationTime);
|
||||
}
|
||||
|
||||
void afterGettingFrame(unsigned frameSize, unsigned numTruncatedBytes, struct timeval presentationTime)
|
||||
{
|
||||
fPresentationTime = presentationTime;
|
||||
fDurationInMicroseconds = 0;
|
||||
if (numTruncatedBytes > 0)
|
||||
{
|
||||
envir() << "AddMarker::afterGettingFrame(): The input frame data was too large for our buffer size truncated:" << numTruncatedBytes << " bufferSize:" << m_bufferSize << "\n";
|
||||
m_bufferSize += numTruncatedBytes;
|
||||
delete[] m_buffer;
|
||||
m_buffer = new unsigned char[m_bufferSize];
|
||||
fFrameSize = 0;
|
||||
} else {
|
||||
fFrameSize = frameSize + sizeof(marker);
|
||||
if (fFrameSize > fMaxSize) {
|
||||
fNumTruncatedBytes = fFrameSize - fMaxSize;
|
||||
envir() << "AddMarker::afterGettingFrame(): buffer too small truncated:" << fNumTruncatedBytes << " bufferSize:" << fFrameSize << "\n";
|
||||
} else {
|
||||
fNumTruncatedBytes = 0;
|
||||
memcpy(fTo, marker, sizeof(marker));
|
||||
memcpy(fTo+sizeof(marker), m_buffer, frameSize);
|
||||
}
|
||||
}
|
||||
afterGetting(this);
|
||||
}
|
||||
|
||||
virtual void doGetNextFrame() {
|
||||
if (fInputSource != NULL)
|
||||
{
|
||||
fInputSource->getNextFrame(m_buffer, m_bufferSize,
|
||||
afterGettingFrame, this,
|
||||
handleClosure, this);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char* m_buffer;
|
||||
unsigned int m_bufferSize;
|
||||
};
|
||||
|
||||
|
||||
HLSServerMediaSubsession::HLSServerMediaSubsession(UsageEnvironment& env, StreamReplicator* replicator, const std::string& format, unsigned int sliceDuration)
|
||||
: UnicastServerMediaSubsession(env, replicator, "video/MP2T"), m_slice(0)
|
||||
{
|
||||
// Create a source
|
||||
FramedSource* source = replicator->createStreamReplica();
|
||||
|
||||
|
||||
if (format == "video/H264") {
|
||||
// add marker
|
||||
FramedSource* filter = new AddMarker(env, source);
|
||||
// mux to TS
|
||||
MPEG2TransportStreamFromESSource* muxer = MPEG2TransportStreamFromESSource::createNew(env);
|
||||
muxer->addNewVideoSource(filter, 5);
|
||||
source = muxer;
|
||||
} else if (format == "video/H265") {
|
||||
// add marker
|
||||
FramedSource* filter = new AddMarker(env, source);
|
||||
// mux to TS
|
||||
MPEG2TransportStreamFromESSource* muxer = MPEG2TransportStreamFromESSource::createNew(env);
|
||||
muxer->addNewVideoSource(filter, 6);
|
||||
source = muxer;
|
||||
}
|
||||
|
||||
FramedSource* videoSource = createSource(env, source, m_format);
|
||||
|
||||
// Start Playing the HLS Sink
|
||||
m_hlsSink = HLSSink::createNew(env, OutPacketBuffer::maxSize, sliceDuration);
|
||||
m_hlsSink->startPlaying(*videoSource, NULL, NULL);
|
||||
}
|
||||
|
||||
HLSServerMediaSubsession::~HLSServerMediaSubsession()
|
||||
{
|
||||
Medium::close(m_hlsSink);
|
||||
}
|
||||
|
||||
float HLSServerMediaSubsession::getCurrentNPT(void* streamToken)
|
||||
{
|
||||
return (m_hlsSink->firstTime());
|
||||
}
|
||||
|
||||
float HLSServerMediaSubsession::duration() const
|
||||
{
|
||||
return (m_hlsSink->duration());
|
||||
}
|
||||
|
||||
void HLSServerMediaSubsession::seekStream(unsigned clientSessionId, void* streamToken, double& seekNPT, double streamDuration, u_int64_t& numBytes)
|
||||
{
|
||||
m_slice = seekNPT / m_hlsSink->getSliceDuration();
|
||||
seekNPT = m_slice * m_hlsSink->getSliceDuration();
|
||||
numBytes = m_hlsSink->getHLSBufferSize(m_slice);
|
||||
std::cout << "seek seekNPT:" << seekNPT << " slice:" << m_slice << " numBytes:" << numBytes << std::endl;
|
||||
}
|
||||
|
||||
FramedSource* HLSServerMediaSubsession::getStreamSource(void* streamToken)
|
||||
{
|
||||
FramedSource* source = NULL;
|
||||
|
||||
std::string buffer = m_hlsSink->getHLSBuffer(m_slice);
|
||||
unsigned int size = buffer.size();
|
||||
if ( size != 0 ) {
|
||||
u_int8_t* content = new u_int8_t[size];
|
||||
memcpy(content, buffer.c_str(), size);
|
||||
source = ByteStreamMemoryBufferSource::createNew(envir(), content, size);
|
||||
}
|
||||
return source;
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
/* ---------------------------------------------------------------------------
|
||||
** This software is in the public domain, furnished "as is", without technical
|
||||
** support, and with no warranty, express or implied, as to its usefulness for
|
||||
** any purpose.
|
||||
**
|
||||
** TSServerMediaSubsession.cpp
|
||||
**
|
||||
** -------------------------------------------------------------------------*/
|
||||
|
||||
#include "TSServerMediaSubsession.h"
|
||||
#include "AddH26xMarkerFilter.h"
|
||||
|
||||
TSServerMediaSubsession::TSServerMediaSubsession(UsageEnvironment& env, StreamReplicator* replicator, const std::string& format, unsigned int sliceDuration)
|
||||
: UnicastServerMediaSubsession(env, replicator, "video/MP2T"), m_slice(0)
|
||||
{
|
||||
// Create a source
|
||||
FramedSource* source = replicator->createStreamReplica();
|
||||
|
||||
|
||||
if (format == "video/H264") {
|
||||
// add marker
|
||||
FramedSource* filter = new AddH26xMarkerFilter(env, source);
|
||||
// mux to TS
|
||||
MPEG2TransportStreamFromESSource* muxer = MPEG2TransportStreamFromESSource::createNew(env);
|
||||
muxer->addNewVideoSource(filter, 5);
|
||||
source = muxer;
|
||||
} else if (format == "video/H265") {
|
||||
// add marker
|
||||
FramedSource* filter = new AddH26xMarkerFilter(env, source);
|
||||
// mux to TS
|
||||
MPEG2TransportStreamFromESSource* muxer = MPEG2TransportStreamFromESSource::createNew(env);
|
||||
muxer->addNewVideoSource(filter, 6);
|
||||
source = muxer;
|
||||
}
|
||||
|
||||
FramedSource* videoSource = createSource(env, source, m_format);
|
||||
|
||||
// Start Playing the HLS Sink
|
||||
m_hlsSink = MemoryBufferSink::createNew(env, OutPacketBuffer::maxSize, sliceDuration);
|
||||
m_hlsSink->startPlaying(*videoSource, NULL, NULL);
|
||||
}
|
||||
|
||||
TSServerMediaSubsession::~TSServerMediaSubsession()
|
||||
{
|
||||
Medium::close(m_hlsSink);
|
||||
}
|
||||
|
||||
float TSServerMediaSubsession::getCurrentNPT(void* streamToken)
|
||||
{
|
||||
return (m_hlsSink->firstTime());
|
||||
}
|
||||
|
||||
float TSServerMediaSubsession::duration() const
|
||||
{
|
||||
return (m_hlsSink->duration());
|
||||
}
|
||||
|
||||
void TSServerMediaSubsession::seekStream(unsigned clientSessionId, void* streamToken, double& seekNPT, double streamDuration, u_int64_t& numBytes)
|
||||
{
|
||||
m_slice = seekNPT / m_hlsSink->getSliceDuration();
|
||||
seekNPT = m_slice * m_hlsSink->getSliceDuration();
|
||||
numBytes = m_hlsSink->getBufferSize(m_slice);
|
||||
std::cout << "seek seekNPT:" << seekNPT << " slice:" << m_slice << " numBytes:" << numBytes << std::endl;
|
||||
}
|
||||
|
||||
FramedSource* TSServerMediaSubsession::getStreamSource(void* streamToken)
|
||||
{
|
||||
FramedSource* source = NULL;
|
||||
|
||||
std::string buffer = m_hlsSink->getBuffer(m_slice);
|
||||
unsigned int size = buffer.size();
|
||||
if ( size != 0 ) {
|
||||
u_int8_t* content = new u_int8_t[size];
|
||||
memcpy(content, buffer.c_str(), size);
|
||||
source = ByteStreamMemoryBufferSource::createNew(envir(), content, size);
|
||||
}
|
||||
return source;
|
||||
}
|
Loading…
Reference in New Issue