mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
add ts mux framework
This commit is contained in:
parent
4af3982721
commit
385394315d
5 changed files with 155 additions and 4 deletions
|
@ -41,8 +41,13 @@ SrsCodecSample::~SrsCodecSample()
|
||||||
|
|
||||||
void SrsCodecSample::clear()
|
void SrsCodecSample::clear()
|
||||||
{
|
{
|
||||||
cts = 0;
|
is_video = false;
|
||||||
nb_buffers = 0;
|
nb_buffers = 0;
|
||||||
|
|
||||||
|
cts = 0;
|
||||||
|
frame_type = SrsCodecVideoAVCFrameReserved;
|
||||||
|
codec_id = SrsCodecVideoReserved;
|
||||||
|
avc_packet_type = SrsCodecVideoAVCTypeReserved;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsCodecSample::add_sample(char* bytes, int size)
|
int SrsCodecSample::add_sample(char* bytes, int size)
|
||||||
|
@ -99,6 +104,8 @@ int SrsCodec::audio_aac_demux(int8_t* data, int size, SrsCodecSample* sample)
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
sample->is_video = false;
|
||||||
|
|
||||||
if (!data || size <= 0) {
|
if (!data || size <= 0) {
|
||||||
srs_trace("no audio present, hls ignore it.");
|
srs_trace("no audio present, hls ignore it.");
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -176,6 +183,8 @@ int SrsCodec::video_avc_demux(int8_t* data, int size, SrsCodecSample* sample)
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
sample->is_video = true;
|
||||||
|
|
||||||
if (!data || size <= 0) {
|
if (!data || size <= 0) {
|
||||||
srs_trace("no video present, hls ignore it.");
|
srs_trace("no video present, hls ignore it.");
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -196,13 +205,16 @@ int SrsCodec::video_avc_demux(int8_t* data, int size, SrsCodecSample* sample)
|
||||||
int8_t codec_id = frame_type & 0x0f;
|
int8_t codec_id = frame_type & 0x0f;
|
||||||
frame_type = (frame_type >> 4) & 0x0f;
|
frame_type = (frame_type >> 4) & 0x0f;
|
||||||
|
|
||||||
video_codec_id = codec_id;
|
sample->frame_type = (SrsCodecVideoAVCFrame)frame_type;
|
||||||
|
sample->codec_id = (SrsCodecVideo)codec_id;
|
||||||
|
|
||||||
// only support h.264/avc
|
// only support h.264/avc
|
||||||
if (codec_id != SrsCodecVideoAVC) {
|
if (codec_id != SrsCodecVideoAVC) {
|
||||||
ret = ERROR_HLS_DECODE_ERROR;
|
ret = ERROR_HLS_DECODE_ERROR;
|
||||||
srs_error("hls only support video h.264/avc codec. ret=%d", ret);
|
srs_error("hls only support video h.264/avc codec. ret=%d", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
video_codec_id = codec_id;
|
||||||
|
|
||||||
if (!stream->require(4)) {
|
if (!stream->require(4)) {
|
||||||
ret = ERROR_HLS_DECODE_ERROR;
|
ret = ERROR_HLS_DECODE_ERROR;
|
||||||
|
@ -214,6 +226,7 @@ int SrsCodec::video_avc_demux(int8_t* data, int size, SrsCodecSample* sample)
|
||||||
|
|
||||||
// pts = dts + cts.
|
// pts = dts + cts.
|
||||||
sample->cts = composition_time;
|
sample->cts = composition_time;
|
||||||
|
sample->avc_packet_type = (SrsCodecVideoAVCType)avc_packet_type;
|
||||||
|
|
||||||
if (avc_packet_type == SrsCodecVideoAVCTypeSequenceHeader) {
|
if (avc_packet_type == SrsCodecVideoAVCTypeSequenceHeader) {
|
||||||
// AVCDecoderConfigurationRecord
|
// AVCDecoderConfigurationRecord
|
||||||
|
|
|
@ -45,6 +45,8 @@ class SrsStream;
|
||||||
// 7 = AVC
|
// 7 = AVC
|
||||||
enum SrsCodecVideo
|
enum SrsCodecVideo
|
||||||
{
|
{
|
||||||
|
SrsCodecVideoReserved = 0,
|
||||||
|
|
||||||
SrsCodecVideoSorensonH263 = 2,
|
SrsCodecVideoSorensonH263 = 2,
|
||||||
SrsCodecVideoScreenVideo = 3,
|
SrsCodecVideoScreenVideo = 3,
|
||||||
SrsCodecVideoOn2VP6 = 4,
|
SrsCodecVideoOn2VP6 = 4,
|
||||||
|
@ -63,6 +65,8 @@ enum SrsCodecVideo
|
||||||
// 5 = video info/command frame
|
// 5 = video info/command frame
|
||||||
enum SrsCodecVideoAVCFrame
|
enum SrsCodecVideoAVCFrame
|
||||||
{
|
{
|
||||||
|
SrsCodecVideoAVCFrameReserved = 0,
|
||||||
|
|
||||||
SrsCodecVideoAVCFrameKeyFrame = 1,
|
SrsCodecVideoAVCFrameKeyFrame = 1,
|
||||||
SrsCodecVideoAVCFrameInterFrame = 2,
|
SrsCodecVideoAVCFrameInterFrame = 2,
|
||||||
SrsCodecVideoAVCFrameDisposableInterFrame = 3,
|
SrsCodecVideoAVCFrameDisposableInterFrame = 3,
|
||||||
|
@ -78,6 +82,8 @@ enum SrsCodecVideoAVCFrame
|
||||||
// not required or supported)
|
// not required or supported)
|
||||||
enum SrsCodecVideoAVCType
|
enum SrsCodecVideoAVCType
|
||||||
{
|
{
|
||||||
|
SrsCodecVideoAVCTypeReserved = -1,
|
||||||
|
|
||||||
SrsCodecVideoAVCTypeSequenceHeader = 0,
|
SrsCodecVideoAVCTypeSequenceHeader = 0,
|
||||||
SrsCodecVideoAVCTypeNALU = 1,
|
SrsCodecVideoAVCTypeNALU = 1,
|
||||||
SrsCodecVideoAVCTypeSequenceHeaderEOF = 2,
|
SrsCodecVideoAVCTypeSequenceHeaderEOF = 2,
|
||||||
|
@ -180,9 +186,14 @@ class SrsCodecSample
|
||||||
public:
|
public:
|
||||||
int nb_buffers;
|
int nb_buffers;
|
||||||
SrsCodecBuffer buffers[SRS_MAX_CODEC_SAMPLE];
|
SrsCodecBuffer buffers[SRS_MAX_CODEC_SAMPLE];
|
||||||
|
public:
|
||||||
|
bool is_video;
|
||||||
// CompositionTime, video_file_format_spec_v10_1.pdf, page 78.
|
// CompositionTime, video_file_format_spec_v10_1.pdf, page 78.
|
||||||
// cts = pts - dts, where dts = flvheader->timestamp.
|
// cts = pts - dts, where dts = flvheader->timestamp.
|
||||||
int32_t cts;
|
int32_t cts;
|
||||||
|
SrsCodecVideoAVCFrame frame_type;
|
||||||
|
SrsCodecVideo codec_id;
|
||||||
|
SrsCodecVideoAVCType avc_packet_type;
|
||||||
public:
|
public:
|
||||||
SrsCodecSample();
|
SrsCodecSample();
|
||||||
virtual ~SrsCodecSample();
|
virtual ~SrsCodecSample();
|
||||||
|
|
|
@ -110,5 +110,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#define ERROR_HLS_METADATA 600
|
#define ERROR_HLS_METADATA 600
|
||||||
#define ERROR_HLS_DECODE_ERROR 601
|
#define ERROR_HLS_DECODE_ERROR 601
|
||||||
#define ERROR_HLS_BUSY 602
|
#define ERROR_HLS_BUSY 602
|
||||||
|
#define ERROR_HLS_OPEN_FAILED 603
|
||||||
|
#define ERROR_HLS_WRITE_FAILED 604
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -23,6 +23,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
#include <srs_core_hls.hpp>
|
#include <srs_core_hls.hpp>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
#include <srs_core_error.hpp>
|
#include <srs_core_error.hpp>
|
||||||
#include <srs_core_codec.hpp>
|
#include <srs_core_codec.hpp>
|
||||||
#include <srs_core_amf0.hpp>
|
#include <srs_core_amf0.hpp>
|
||||||
|
@ -63,6 +67,9 @@ int SrsHLS::on_publish(std::string _vhost)
|
||||||
if (!conf && conf->arg0() == "off") {
|
if (!conf && conf->arg0() == "off") {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: check the audio and video, ensure both exsists.
|
||||||
|
// for use fixed mpegts header specifeid the audio and video pid.
|
||||||
|
|
||||||
hls_enabled = true;
|
hls_enabled = true;
|
||||||
|
|
||||||
|
@ -71,6 +78,9 @@ int SrsHLS::on_publish(std::string _vhost)
|
||||||
path = conf->arg0();
|
path = conf->arg0();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: generate by m3u8 muxer.
|
||||||
|
path += "/1.ts";
|
||||||
|
|
||||||
if ((ret = muxer->open(path)) != ERROR_SUCCESS) {
|
if ((ret = muxer->open(path)) != ERROR_SUCCESS) {
|
||||||
srs_error("open hls muxer failed. ret=%d", ret);
|
srs_error("open hls muxer failed. ret=%d", ret);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -82,6 +92,7 @@ int SrsHLS::on_publish(std::string _vhost)
|
||||||
void SrsHLS::on_unpublish()
|
void SrsHLS::on_unpublish()
|
||||||
{
|
{
|
||||||
hls_enabled = false;
|
hls_enabled = false;
|
||||||
|
muxer->close();
|
||||||
srs_freep(muxer);
|
srs_freep(muxer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,6 +196,10 @@ int SrsHLS::on_audio(SrsCommonMessage* audio)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((ret = muxer->write(codec, sample)) != ERROR_SUCCESS) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,20 +221,125 @@ int SrsHLS::on_video(SrsCommonMessage* video)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((ret = muxer->write(codec, sample)) != ERROR_SUCCESS) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @see: ngx_rtmp_mpegts_header
|
||||||
|
static u_char mpegts_header[] = {
|
||||||
|
/* TS */
|
||||||
|
0x47, 0x40, 0x00, 0x10, 0x00,
|
||||||
|
/* PSI */
|
||||||
|
0x00, 0xb0, 0x0d, 0x00, 0x01, 0xc1, 0x00, 0x00,
|
||||||
|
/* PAT */
|
||||||
|
0x00, 0x01, 0xf0, 0x01,
|
||||||
|
/* CRC */
|
||||||
|
0x2e, 0x70, 0x19, 0x05,
|
||||||
|
/* stuffing 167 bytes */
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
|
||||||
|
/* TS */
|
||||||
|
0x47, 0x50, 0x01, 0x10, 0x00,
|
||||||
|
/* PSI */
|
||||||
|
0x02, 0xb0, 0x17, 0x00, 0x01, 0xc1, 0x00, 0x00,
|
||||||
|
/* PMT */
|
||||||
|
0xe1, 0x00,
|
||||||
|
0xf0, 0x00,
|
||||||
|
0x1b, 0xe1, 0x00, 0xf0, 0x00, /* h264, pid=0x100=256 */
|
||||||
|
0x0f, 0xe1, 0x01, 0xf0, 0x00, /* aac, pid=0x101=257 */
|
||||||
|
/*0x03, 0xe1, 0x01, 0xf0, 0x00,*/ /* mp3 */
|
||||||
|
/* CRC */
|
||||||
|
0x2f, 0x44, 0xb9, 0x9b, /* crc for aac */
|
||||||
|
/*0x4e, 0x59, 0x3d, 0x1e,*/ /* crc for mp3 */
|
||||||
|
/* stuffing 157 bytes */
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
|
||||||
|
};
|
||||||
|
|
||||||
|
// the mpegts header specifed the video/audio pid.
|
||||||
|
#define TS_VIDEO_PID 256
|
||||||
|
#define TS_AUDIO_PID 257
|
||||||
|
|
||||||
SrsTSMuxer::SrsTSMuxer()
|
SrsTSMuxer::SrsTSMuxer()
|
||||||
{
|
{
|
||||||
|
fd = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsTSMuxer::~SrsTSMuxer()
|
SrsTSMuxer::~SrsTSMuxer()
|
||||||
{
|
{
|
||||||
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsTSMuxer::open(std::string path)
|
int SrsTSMuxer::open(std::string _path)
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
path = _path;
|
||||||
|
|
||||||
|
close();
|
||||||
|
|
||||||
|
int flags = O_CREAT|O_WRONLY|O_TRUNC;
|
||||||
|
mode_t mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH;
|
||||||
|
if ((fd = ::open(path.c_str(), flags, mode)) < 0) {
|
||||||
|
ret = ERROR_HLS_OPEN_FAILED;
|
||||||
|
srs_error("open ts file %s failed. ret=%d", path.c_str(), ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// write mpegts header
|
||||||
|
if (::write(fd, mpegts_header, sizeof(mpegts_header)) != sizeof(mpegts_header)) {
|
||||||
|
ret = ERROR_HLS_WRITE_FAILED;
|
||||||
|
srs_error("write ts file header %s failed. ret=%d", path.c_str(), ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsTSMuxer::write(SrsCodec* codec, SrsCodecSample* sample)
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SrsTSMuxer::close()
|
||||||
|
{
|
||||||
|
if (fd > 0) {
|
||||||
|
::close(fd);
|
||||||
|
fd = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,11 +58,16 @@ public:
|
||||||
|
|
||||||
class SrsTSMuxer
|
class SrsTSMuxer
|
||||||
{
|
{
|
||||||
|
private:
|
||||||
|
int fd;
|
||||||
|
std::string path;
|
||||||
public:
|
public:
|
||||||
SrsTSMuxer();
|
SrsTSMuxer();
|
||||||
virtual ~SrsTSMuxer();
|
virtual ~SrsTSMuxer();
|
||||||
public:
|
public:
|
||||||
virtual int open(std::string path);
|
virtual int open(std::string _path);
|
||||||
|
virtual int write(SrsCodec* codec, SrsCodecSample* sample);
|
||||||
|
virtual void close();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
Loading…
Add table
Add a link
Reference in a new issue