winlin

add ts mux framework

... ... @@ -41,8 +41,13 @@ SrsCodecSample::~SrsCodecSample()
void SrsCodecSample::clear()
{
cts = 0;
is_video = false;
nb_buffers = 0;
cts = 0;
frame_type = SrsCodecVideoAVCFrameReserved;
codec_id = SrsCodecVideoReserved;
avc_packet_type = SrsCodecVideoAVCTypeReserved;
}
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;
sample->is_video = false;
if (!data || size <= 0) {
srs_trace("no audio present, hls ignore it.");
return ret;
... ... @@ -176,6 +183,8 @@ int SrsCodec::video_avc_demux(int8_t* data, int size, SrsCodecSample* sample)
{
int ret = ERROR_SUCCESS;
sample->is_video = true;
if (!data || size <= 0) {
srs_trace("no video present, hls ignore it.");
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;
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
if (codec_id != SrsCodecVideoAVC) {
ret = ERROR_HLS_DECODE_ERROR;
srs_error("hls only support video h.264/avc codec. ret=%d", ret);
return ret;
}
video_codec_id = codec_id;
if (!stream->require(4)) {
ret = ERROR_HLS_DECODE_ERROR;
... ... @@ -214,6 +226,7 @@ int SrsCodec::video_avc_demux(int8_t* data, int size, SrsCodecSample* sample)
// pts = dts + cts.
sample->cts = composition_time;
sample->avc_packet_type = (SrsCodecVideoAVCType)avc_packet_type;
if (avc_packet_type == SrsCodecVideoAVCTypeSequenceHeader) {
// AVCDecoderConfigurationRecord
... ...
... ... @@ -45,6 +45,8 @@ class SrsStream;
// 7 = AVC
enum SrsCodecVideo
{
SrsCodecVideoReserved = 0,
SrsCodecVideoSorensonH263 = 2,
SrsCodecVideoScreenVideo = 3,
SrsCodecVideoOn2VP6 = 4,
... ... @@ -63,6 +65,8 @@ enum SrsCodecVideo
// 5 = video info/command frame
enum SrsCodecVideoAVCFrame
{
SrsCodecVideoAVCFrameReserved = 0,
SrsCodecVideoAVCFrameKeyFrame = 1,
SrsCodecVideoAVCFrameInterFrame = 2,
SrsCodecVideoAVCFrameDisposableInterFrame = 3,
... ... @@ -78,6 +82,8 @@ enum SrsCodecVideoAVCFrame
// not required or supported)
enum SrsCodecVideoAVCType
{
SrsCodecVideoAVCTypeReserved = -1,
SrsCodecVideoAVCTypeSequenceHeader = 0,
SrsCodecVideoAVCTypeNALU = 1,
SrsCodecVideoAVCTypeSequenceHeaderEOF = 2,
... ... @@ -180,9 +186,14 @@ class SrsCodecSample
public:
int nb_buffers;
SrsCodecBuffer buffers[SRS_MAX_CODEC_SAMPLE];
public:
bool is_video;
// CompositionTime, video_file_format_spec_v10_1.pdf, page 78.
// cts = pts - dts, where dts = flvheader->timestamp.
int32_t cts;
SrsCodecVideoAVCFrame frame_type;
SrsCodecVideo codec_id;
SrsCodecVideoAVCType avc_packet_type;
public:
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_DECODE_ERROR 601
#define ERROR_HLS_BUSY 602
#define ERROR_HLS_OPEN_FAILED 603
#define ERROR_HLS_WRITE_FAILED 604
#endif
\ No newline at end of file
... ...
... ... @@ -23,6 +23,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <srs_core_hls.hpp>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <srs_core_error.hpp>
#include <srs_core_codec.hpp>
#include <srs_core_amf0.hpp>
... ... @@ -64,6 +68,9 @@ int SrsHLS::on_publish(std::string _vhost)
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;
std::string path = SRS_CONF_DEFAULT_HLS_PATH;
... ... @@ -71,6 +78,9 @@ int SrsHLS::on_publish(std::string _vhost)
path = conf->arg0();
}
// TODO: generate by m3u8 muxer.
path += "/1.ts";
if ((ret = muxer->open(path)) != ERROR_SUCCESS) {
srs_error("open hls muxer failed. ret=%d", ret);
return ret;
... ... @@ -82,6 +92,7 @@ int SrsHLS::on_publish(std::string _vhost)
void SrsHLS::on_unpublish()
{
hls_enabled = false;
muxer->close();
srs_freep(muxer);
}
... ... @@ -185,6 +196,10 @@ int SrsHLS::on_audio(SrsCommonMessage* audio)
return ret;
}
if ((ret = muxer->write(codec, sample)) != ERROR_SUCCESS) {
return ret;
}
return ret;
}
... ... @@ -206,20 +221,125 @@ int SrsHLS::on_video(SrsCommonMessage* video)
return ret;
}
if ((ret = muxer->write(codec, sample)) != ERROR_SUCCESS) {
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()
{
fd = -1;
}
SrsTSMuxer::~SrsTSMuxer()
{
close();
}
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::open(std::string path)
int SrsTSMuxer::write(SrsCodec* codec, SrsCodecSample* sample)
{
int ret = ERROR_SUCCESS;
return ret;
}
void SrsTSMuxer::close()
{
if (fd > 0) {
::close(fd);
fd = -1;
}
}
... ...
... ... @@ -58,11 +58,16 @@ public:
class SrsTSMuxer
{
private:
int fd;
std::string path;
public:
SrsTSMuxer();
virtual ~SrsTSMuxer();
public:
virtual int open(std::string path);
virtual int open(std::string _path);
virtual int write(SrsCodec* codec, SrsCodecSample* sample);
virtual void close();
};
#endif
\ No newline at end of file
... ...