winlin

add ts mux framework

@@ -41,8 +41,13 @@ SrsCodecSample::~SrsCodecSample() @@ -41,8 +41,13 @@ SrsCodecSample::~SrsCodecSample()
41 41
42 void SrsCodecSample::clear() 42 void SrsCodecSample::clear()
43 { 43 {
44 - cts = 0; 44 + is_video = false;
45 nb_buffers = 0; 45 nb_buffers = 0;
  46 +
  47 + cts = 0;
  48 + frame_type = SrsCodecVideoAVCFrameReserved;
  49 + codec_id = SrsCodecVideoReserved;
  50 + avc_packet_type = SrsCodecVideoAVCTypeReserved;
46 } 51 }
47 52
48 int SrsCodecSample::add_sample(char* bytes, int size) 53 int SrsCodecSample::add_sample(char* bytes, int size)
@@ -99,6 +104,8 @@ int SrsCodec::audio_aac_demux(int8_t* data, int size, SrsCodecSample* sample) @@ -99,6 +104,8 @@ int SrsCodec::audio_aac_demux(int8_t* data, int size, SrsCodecSample* sample)
99 { 104 {
100 int ret = ERROR_SUCCESS; 105 int ret = ERROR_SUCCESS;
101 106
  107 + sample->is_video = false;
  108 +
102 if (!data || size <= 0) { 109 if (!data || size <= 0) {
103 srs_trace("no audio present, hls ignore it."); 110 srs_trace("no audio present, hls ignore it.");
104 return ret; 111 return ret;
@@ -176,6 +183,8 @@ int SrsCodec::video_avc_demux(int8_t* data, int size, SrsCodecSample* sample) @@ -176,6 +183,8 @@ int SrsCodec::video_avc_demux(int8_t* data, int size, SrsCodecSample* sample)
176 { 183 {
177 int ret = ERROR_SUCCESS; 184 int ret = ERROR_SUCCESS;
178 185
  186 + sample->is_video = true;
  187 +
179 if (!data || size <= 0) { 188 if (!data || size <= 0) {
180 srs_trace("no video present, hls ignore it."); 189 srs_trace("no video present, hls ignore it.");
181 return ret; 190 return ret;
@@ -196,13 +205,16 @@ int SrsCodec::video_avc_demux(int8_t* data, int size, SrsCodecSample* sample) @@ -196,13 +205,16 @@ int SrsCodec::video_avc_demux(int8_t* data, int size, SrsCodecSample* sample)
196 int8_t codec_id = frame_type & 0x0f; 205 int8_t codec_id = frame_type & 0x0f;
197 frame_type = (frame_type >> 4) & 0x0f; 206 frame_type = (frame_type >> 4) & 0x0f;
198 207
199 - video_codec_id = codec_id; 208 + sample->frame_type = (SrsCodecVideoAVCFrame)frame_type;
  209 + sample->codec_id = (SrsCodecVideo)codec_id;
  210 +
200 // only support h.264/avc 211 // only support h.264/avc
201 if (codec_id != SrsCodecVideoAVC) { 212 if (codec_id != SrsCodecVideoAVC) {
202 ret = ERROR_HLS_DECODE_ERROR; 213 ret = ERROR_HLS_DECODE_ERROR;
203 srs_error("hls only support video h.264/avc codec. ret=%d", ret); 214 srs_error("hls only support video h.264/avc codec. ret=%d", ret);
204 return ret; 215 return ret;
205 } 216 }
  217 + video_codec_id = codec_id;
206 218
207 if (!stream->require(4)) { 219 if (!stream->require(4)) {
208 ret = ERROR_HLS_DECODE_ERROR; 220 ret = ERROR_HLS_DECODE_ERROR;
@@ -214,6 +226,7 @@ int SrsCodec::video_avc_demux(int8_t* data, int size, SrsCodecSample* sample) @@ -214,6 +226,7 @@ int SrsCodec::video_avc_demux(int8_t* data, int size, SrsCodecSample* sample)
214 226
215 // pts = dts + cts. 227 // pts = dts + cts.
216 sample->cts = composition_time; 228 sample->cts = composition_time;
  229 + sample->avc_packet_type = (SrsCodecVideoAVCType)avc_packet_type;
217 230
218 if (avc_packet_type == SrsCodecVideoAVCTypeSequenceHeader) { 231 if (avc_packet_type == SrsCodecVideoAVCTypeSequenceHeader) {
219 // AVCDecoderConfigurationRecord 232 // AVCDecoderConfigurationRecord
@@ -45,6 +45,8 @@ class SrsStream; @@ -45,6 +45,8 @@ class SrsStream;
45 // 7 = AVC 45 // 7 = AVC
46 enum SrsCodecVideo 46 enum SrsCodecVideo
47 { 47 {
  48 + SrsCodecVideoReserved = 0,
  49 +
48 SrsCodecVideoSorensonH263 = 2, 50 SrsCodecVideoSorensonH263 = 2,
49 SrsCodecVideoScreenVideo = 3, 51 SrsCodecVideoScreenVideo = 3,
50 SrsCodecVideoOn2VP6 = 4, 52 SrsCodecVideoOn2VP6 = 4,
@@ -63,6 +65,8 @@ enum SrsCodecVideo @@ -63,6 +65,8 @@ enum SrsCodecVideo
63 // 5 = video info/command frame 65 // 5 = video info/command frame
64 enum SrsCodecVideoAVCFrame 66 enum SrsCodecVideoAVCFrame
65 { 67 {
  68 + SrsCodecVideoAVCFrameReserved = 0,
  69 +
66 SrsCodecVideoAVCFrameKeyFrame = 1, 70 SrsCodecVideoAVCFrameKeyFrame = 1,
67 SrsCodecVideoAVCFrameInterFrame = 2, 71 SrsCodecVideoAVCFrameInterFrame = 2,
68 SrsCodecVideoAVCFrameDisposableInterFrame = 3, 72 SrsCodecVideoAVCFrameDisposableInterFrame = 3,
@@ -78,6 +82,8 @@ enum SrsCodecVideoAVCFrame @@ -78,6 +82,8 @@ enum SrsCodecVideoAVCFrame
78 // not required or supported) 82 // not required or supported)
79 enum SrsCodecVideoAVCType 83 enum SrsCodecVideoAVCType
80 { 84 {
  85 + SrsCodecVideoAVCTypeReserved = -1,
  86 +
81 SrsCodecVideoAVCTypeSequenceHeader = 0, 87 SrsCodecVideoAVCTypeSequenceHeader = 0,
82 SrsCodecVideoAVCTypeNALU = 1, 88 SrsCodecVideoAVCTypeNALU = 1,
83 SrsCodecVideoAVCTypeSequenceHeaderEOF = 2, 89 SrsCodecVideoAVCTypeSequenceHeaderEOF = 2,
@@ -180,9 +186,14 @@ class SrsCodecSample @@ -180,9 +186,14 @@ class SrsCodecSample
180 public: 186 public:
181 int nb_buffers; 187 int nb_buffers;
182 SrsCodecBuffer buffers[SRS_MAX_CODEC_SAMPLE]; 188 SrsCodecBuffer buffers[SRS_MAX_CODEC_SAMPLE];
  189 +public:
  190 + bool is_video;
183 // CompositionTime, video_file_format_spec_v10_1.pdf, page 78. 191 // CompositionTime, video_file_format_spec_v10_1.pdf, page 78.
184 // cts = pts - dts, where dts = flvheader->timestamp. 192 // cts = pts - dts, where dts = flvheader->timestamp.
185 int32_t cts; 193 int32_t cts;
  194 + SrsCodecVideoAVCFrame frame_type;
  195 + SrsCodecVideo codec_id;
  196 + SrsCodecVideoAVCType avc_packet_type;
186 public: 197 public:
187 SrsCodecSample(); 198 SrsCodecSample();
188 virtual ~SrsCodecSample(); 199 virtual ~SrsCodecSample();
@@ -110,5 +110,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -110,5 +110,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
110 #define ERROR_HLS_METADATA 600 110 #define ERROR_HLS_METADATA 600
111 #define ERROR_HLS_DECODE_ERROR 601 111 #define ERROR_HLS_DECODE_ERROR 601
112 #define ERROR_HLS_BUSY 602 112 #define ERROR_HLS_BUSY 602
  113 +#define ERROR_HLS_OPEN_FAILED 603
  114 +#define ERROR_HLS_WRITE_FAILED 604
113 115
114 #endif 116 #endif
@@ -23,6 +23,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -23,6 +23,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 23
24 #include <srs_core_hls.hpp> 24 #include <srs_core_hls.hpp>
25 25
  26 +#include <sys/types.h>
  27 +#include <sys/stat.h>
  28 +#include <fcntl.h>
  29 +
26 #include <srs_core_error.hpp> 30 #include <srs_core_error.hpp>
27 #include <srs_core_codec.hpp> 31 #include <srs_core_codec.hpp>
28 #include <srs_core_amf0.hpp> 32 #include <srs_core_amf0.hpp>
@@ -63,6 +67,9 @@ int SrsHLS::on_publish(std::string _vhost) @@ -63,6 +67,9 @@ int SrsHLS::on_publish(std::string _vhost)
63 if (!conf && conf->arg0() == "off") { 67 if (!conf && conf->arg0() == "off") {
64 return ret; 68 return ret;
65 } 69 }
  70 +
  71 + // TODO: check the audio and video, ensure both exsists.
  72 + // for use fixed mpegts header specifeid the audio and video pid.
66 73
67 hls_enabled = true; 74 hls_enabled = true;
68 75
@@ -71,6 +78,9 @@ int SrsHLS::on_publish(std::string _vhost) @@ -71,6 +78,9 @@ int SrsHLS::on_publish(std::string _vhost)
71 path = conf->arg0(); 78 path = conf->arg0();
72 } 79 }
73 80
  81 + // TODO: generate by m3u8 muxer.
  82 + path += "/1.ts";
  83 +
74 if ((ret = muxer->open(path)) != ERROR_SUCCESS) { 84 if ((ret = muxer->open(path)) != ERROR_SUCCESS) {
75 srs_error("open hls muxer failed. ret=%d", ret); 85 srs_error("open hls muxer failed. ret=%d", ret);
76 return ret; 86 return ret;
@@ -82,6 +92,7 @@ int SrsHLS::on_publish(std::string _vhost) @@ -82,6 +92,7 @@ int SrsHLS::on_publish(std::string _vhost)
82 void SrsHLS::on_unpublish() 92 void SrsHLS::on_unpublish()
83 { 93 {
84 hls_enabled = false; 94 hls_enabled = false;
  95 + muxer->close();
85 srs_freep(muxer); 96 srs_freep(muxer);
86 } 97 }
87 98
@@ -185,6 +196,10 @@ int SrsHLS::on_audio(SrsCommonMessage* audio) @@ -185,6 +196,10 @@ int SrsHLS::on_audio(SrsCommonMessage* audio)
185 return ret; 196 return ret;
186 } 197 }
187 198
  199 + if ((ret = muxer->write(codec, sample)) != ERROR_SUCCESS) {
  200 + return ret;
  201 + }
  202 +
188 return ret; 203 return ret;
189 } 204 }
190 205
@@ -206,20 +221,125 @@ int SrsHLS::on_video(SrsCommonMessage* video) @@ -206,20 +221,125 @@ int SrsHLS::on_video(SrsCommonMessage* video)
206 return ret; 221 return ret;
207 } 222 }
208 223
  224 + if ((ret = muxer->write(codec, sample)) != ERROR_SUCCESS) {
  225 + return ret;
  226 + }
  227 +
209 return ret; 228 return ret;
210 } 229 }
211 230
  231 +// @see: ngx_rtmp_mpegts_header
  232 +static u_char mpegts_header[] = {
  233 + /* TS */
  234 + 0x47, 0x40, 0x00, 0x10, 0x00,
  235 + /* PSI */
  236 + 0x00, 0xb0, 0x0d, 0x00, 0x01, 0xc1, 0x00, 0x00,
  237 + /* PAT */
  238 + 0x00, 0x01, 0xf0, 0x01,
  239 + /* CRC */
  240 + 0x2e, 0x70, 0x19, 0x05,
  241 + /* stuffing 167 bytes */
  242 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  243 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  244 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  245 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  246 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  247 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  248 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  249 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  250 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  251 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  252 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  253 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  254 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  255 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  256 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  257 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  258 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  259 +
  260 + /* TS */
  261 + 0x47, 0x50, 0x01, 0x10, 0x00,
  262 + /* PSI */
  263 + 0x02, 0xb0, 0x17, 0x00, 0x01, 0xc1, 0x00, 0x00,
  264 + /* PMT */
  265 + 0xe1, 0x00,
  266 + 0xf0, 0x00,
  267 + 0x1b, 0xe1, 0x00, 0xf0, 0x00, /* h264, pid=0x100=256 */
  268 + 0x0f, 0xe1, 0x01, 0xf0, 0x00, /* aac, pid=0x101=257 */
  269 + /*0x03, 0xe1, 0x01, 0xf0, 0x00,*/ /* mp3 */
  270 + /* CRC */
  271 + 0x2f, 0x44, 0xb9, 0x9b, /* crc for aac */
  272 + /*0x4e, 0x59, 0x3d, 0x1e,*/ /* crc for mp3 */
  273 + /* stuffing 157 bytes */
  274 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  275 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  276 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  277 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  278 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  279 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  280 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  281 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  282 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  283 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  284 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  285 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  286 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  287 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  288 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  289 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
  290 +};
  291 +
  292 +// the mpegts header specifed the video/audio pid.
  293 +#define TS_VIDEO_PID 256
  294 +#define TS_AUDIO_PID 257
  295 +
212 SrsTSMuxer::SrsTSMuxer() 296 SrsTSMuxer::SrsTSMuxer()
213 { 297 {
  298 + fd = -1;
214 } 299 }
215 300
216 SrsTSMuxer::~SrsTSMuxer() 301 SrsTSMuxer::~SrsTSMuxer()
217 { 302 {
  303 + close();
218 } 304 }
219 305
220 -int SrsTSMuxer::open(std::string path) 306 +int SrsTSMuxer::open(std::string _path)
  307 +{
  308 + int ret = ERROR_SUCCESS;
  309 +
  310 + path = _path;
  311 +
  312 + close();
  313 +
  314 + int flags = O_CREAT|O_WRONLY|O_TRUNC;
  315 + mode_t mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH;
  316 + if ((fd = ::open(path.c_str(), flags, mode)) < 0) {
  317 + ret = ERROR_HLS_OPEN_FAILED;
  318 + srs_error("open ts file %s failed. ret=%d", path.c_str(), ret);
  319 + return ret;
  320 + }
  321 +
  322 + // write mpegts header
  323 + if (::write(fd, mpegts_header, sizeof(mpegts_header)) != sizeof(mpegts_header)) {
  324 + ret = ERROR_HLS_WRITE_FAILED;
  325 + srs_error("write ts file header %s failed. ret=%d", path.c_str(), ret);
  326 + return ret;
  327 + }
  328 +
  329 + return ret;
  330 +}
  331 +
  332 +int SrsTSMuxer::write(SrsCodec* codec, SrsCodecSample* sample)
221 { 333 {
222 int ret = ERROR_SUCCESS; 334 int ret = ERROR_SUCCESS;
223 return ret; 335 return ret;
224 } 336 }
225 337
  338 +void SrsTSMuxer::close()
  339 +{
  340 + if (fd > 0) {
  341 + ::close(fd);
  342 + fd = -1;
  343 + }
  344 +}
  345 +
@@ -58,11 +58,16 @@ public: @@ -58,11 +58,16 @@ public:
58 58
59 class SrsTSMuxer 59 class SrsTSMuxer
60 { 60 {
  61 +private:
  62 + int fd;
  63 + std::string path;
61 public: 64 public:
62 SrsTSMuxer(); 65 SrsTSMuxer();
63 virtual ~SrsTSMuxer(); 66 virtual ~SrsTSMuxer();
64 public: 67 public:
65 - virtual int open(std::string path); 68 + virtual int open(std::string _path);
  69 + virtual int write(SrsCodec* codec, SrsCodecSample* sample);
  70 + virtual void close();
66 }; 71 };
67 72
68 #endif 73 #endif