winlin

for #304, support config default acodec/vcodec. 2.0.118.

@@ -527,6 +527,7 @@ Supported operating systems and hardware: @@ -527,6 +527,7 @@ Supported operating systems and hardware:
527 527
528 ### SRS 2.0 history 528 ### SRS 2.0 history
529 529
  530 +* v2.0, 2015-02-15, for [#304](https://github.com/winlinvip/simple-rtmp-server/issues/304), support config default acodec/vcodec. 2.0.118.
530 * v2.0, 2015-02-15, for [#304](https://github.com/winlinvip/simple-rtmp-server/issues/304), rewrite hls/ts code, support h.264+mp3 for hls. 2.0.117. 531 * v2.0, 2015-02-15, for [#304](https://github.com/winlinvip/simple-rtmp-server/issues/304), rewrite hls/ts code, support h.264+mp3 for hls. 2.0.117.
531 * v2.0, 2015-02-12, for [#304](https://github.com/winlinvip/simple-rtmp-server/issues/304), use stringstream to generate m3u8, add hls_td_ratio. 2.0.116. 532 * v2.0, 2015-02-12, for [#304](https://github.com/winlinvip/simple-rtmp-server/issues/304), use stringstream to generate m3u8, add hls_td_ratio. 2.0.116.
532 * v2.0, 2015-02-11, dev code ZhouGuowen for 2.0.115. 533 * v2.0, 2015-02-11, dev code ZhouGuowen for 2.0.115.
@@ -495,10 +495,19 @@ vhost with-hls.srs.com { @@ -495,10 +495,19 @@ vhost with-hls.srs.com {
495 # the default audio codec of hls. 495 # the default audio codec of hls.
496 # when codec changed, write the PAT/PMT table, but maybe ok util next ts. 496 # when codec changed, write the PAT/PMT table, but maybe ok util next ts.
497 # so user can set the default codec for mp3. 497 # so user can set the default codec for mp3.
498 - # the available audio codec: aac, mp3 498 + # the available audio codec:
  499 + # aac, mp3
499 # default: aac 500 # default: aac
500 # TODO: FIXME: update wiki for it. 501 # TODO: FIXME: update wiki for it.
501 hls_acodec aac; 502 hls_acodec aac;
  503 + # the default video codec of hls.
  504 + # when codec changed, write the PAT/PMT table, but maybe ok util next ts.
  505 + # so user can set the default codec for pure audio(without video) to vn.
  506 + # the available video codec:
  507 + # h264, vn
  508 + # default: h264
  509 + # TODO: FIXME: update wiki for it.
  510 + hls_vcodec h264;
502 } 511 }
503 } 512 }
504 # the vhost with hls disabled. 513 # the vhost with hls disabled.
@@ -713,9 +722,9 @@ vhost example.transcode.srs.com { @@ -713,9 +722,9 @@ vhost example.transcode.srs.com {
713 filter_complex 'overlay=10:10'; 722 filter_complex 'overlay=10:10';
714 } 723 }
715 # video encoder name. can be: 724 # video encoder name. can be:
716 - # libx264: use h.264(libx264) video encoder.  
717 - # copy: donot encoder the video stream, copy it.  
718 - # vn: disable video output. 725 + # libx264: use h.264(libx264) video encoder.
  726 + # copy: donot encoder the video stream, copy it.
  727 + # vn: disable video output.
719 vcodec libx264; 728 vcodec libx264;
720 # video bitrate, in kbps 729 # video bitrate, in kbps
721 vbitrate 1500; 730 vbitrate 1500;
@@ -731,8 +740,8 @@ vhost example.transcode.srs.com { @@ -731,8 +740,8 @@ vhost example.transcode.srs.com {
731 # high,main,baseline 740 # high,main,baseline
732 vprofile main; 741 vprofile main;
733 # x264 preset, @see x264 -help, can be: 742 # x264 preset, @see x264 -help, can be:
734 - # ultrafast,superfast,veryfast,faster,fast  
735 - # medium,slow,slower,veryslow,placebo 743 + # ultrafast,superfast,veryfast,faster,fast
  744 + # medium,slow,slower,veryslow,placebo
736 vpreset medium; 745 vpreset medium;
737 # other x264 or ffmpeg video params 746 # other x264 or ffmpeg video params
738 vparams { 747 vparams {
@@ -745,14 +754,15 @@ vhost example.transcode.srs.com { @@ -745,14 +754,15 @@ vhost example.transcode.srs.com {
745 refs 10; 754 refs 10;
746 } 755 }
747 # audio encoder name. can be: 756 # audio encoder name. can be:
748 - # libaacplus: use aac(libaacplus) audio encoder.  
749 - # copy: donot encoder the audio stream, copy it.  
750 - # an: disable audio output. 757 + # libaacplus: use aac(libaacplus) audio encoder.
  758 + # libfdk_aac: use aac(libfdk_aac) audio encoder.
  759 + # copy: donot encoder the audio stream, copy it.
  760 + # an: disable audio output.
751 acodec libaacplus; 761 acodec libaacplus;
752 # audio bitrate, in kbps. [16, 72] for libaacplus. 762 # audio bitrate, in kbps. [16, 72] for libaacplus.
753 abitrate 70; 763 abitrate 70;
754 # audio sample rate. for flv/rtmp, it must be: 764 # audio sample rate. for flv/rtmp, it must be:
755 - # 44100,22050,11025,5512 765 + # 44100,22050,11025,5512
756 asample_rate 44100; 766 asample_rate 44100;
757 # audio channel, 1 for mono, 2 for stereo. 767 # audio channel, 1 for mono, 2 for stereo.
758 achannels 2; 768 achannels 2;
@@ -762,17 +772,17 @@ vhost example.transcode.srs.com { @@ -762,17 +772,17 @@ vhost example.transcode.srs.com {
762 profile:a aac_low; 772 profile:a aac_low;
763 } 773 }
764 # output format, can be: 774 # output format, can be:
765 - # off, do not specifies the format, ffmpeg will guess it.  
766 - # flv, for flv or RTMP stream.  
767 - # other format, for example, mp4/aac whatever. 775 + # off, do not specifies the format, ffmpeg will guess it.
  776 + # flv, for flv or RTMP stream.
  777 + # other format, for example, mp4/aac whatever.
768 # default: flv 778 # default: flv
769 oformat flv; 779 oformat flv;
770 # output stream. variables: 780 # output stream. variables:
771 - # [vhost] the input stream vhost.  
772 - # [port] the intput stream port.  
773 - # [app] the input stream app.  
774 - # [stream] the input stream name.  
775 - # [engine] the tanscode engine name. 781 + # [vhost] the input stream vhost.
  782 + # [port] the intput stream port.
  783 + # [app] the input stream app.
  784 + # [stream] the input stream name.
  785 + # [engine] the tanscode engine name.
776 output rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine]; 786 output rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine];
777 } 787 }
778 } 788 }
@@ -1480,7 +1480,7 @@ int SrsConfig::check_config() @@ -1480,7 +1480,7 @@ int SrsConfig::check_config()
1480 for (int j = 0; j < (int)conf->directives.size(); j++) { 1480 for (int j = 0; j < (int)conf->directives.size(); j++) {
1481 string m = conf->at(j)->name.c_str(); 1481 string m = conf->at(j)->name.c_str();
1482 if (m != "enabled" && m != "hls_path" && m != "hls_fragment" && m != "hls_window" && m != "hls_on_error" 1482 if (m != "enabled" && m != "hls_path" && m != "hls_fragment" && m != "hls_window" && m != "hls_on_error"
1483 - && m != "hls_storage" && m != "hls_mount" && m != "hls_td_ratio" && m != "hls_acodec" 1483 + && m != "hls_storage" && m != "hls_mount" && m != "hls_td_ratio" && m != "hls_acodec" && m != "hls_vcodec"
1484 ) { 1484 ) {
1485 ret = ERROR_SYSTEM_CONFIG_INVALID; 1485 ret = ERROR_SYSTEM_CONFIG_INVALID;
1486 srs_error("unsupported vhost hls directive %s, ret=%d", m.c_str(), ret); 1486 srs_error("unsupported vhost hls directive %s, ret=%d", m.c_str(), ret);
@@ -3349,6 +3349,23 @@ string SrsConfig::get_hls_acodec(string vhost) @@ -3349,6 +3349,23 @@ string SrsConfig::get_hls_acodec(string vhost)
3349 return conf->arg0(); 3349 return conf->arg0();
3350 } 3350 }
3351 3351
  3352 +string SrsConfig::get_hls_vcodec(string vhost)
  3353 +{
  3354 + SrsConfDirective* hls = get_hls(vhost);
  3355 +
  3356 + if (!hls) {
  3357 + return SRS_CONF_DEFAULT_HLS_VCODEC;
  3358 + }
  3359 +
  3360 + SrsConfDirective* conf = hls->get("hls_vcodec");
  3361 +
  3362 + if (!conf) {
  3363 + return SRS_CONF_DEFAULT_HLS_VCODEC;
  3364 + }
  3365 +
  3366 + return conf->arg0();
  3367 +}
  3368 +
3352 SrsConfDirective* SrsConfig::get_dvr(string vhost) 3369 SrsConfDirective* SrsConfig::get_dvr(string vhost)
3353 { 3370 {
3354 SrsConfDirective* conf = get_vhost(vhost); 3371 SrsConfDirective* conf = get_vhost(vhost);
@@ -56,6 +56,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -56,6 +56,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
56 #define SRS_CONF_DEFAULT_HLS_STORAGE "disk" 56 #define SRS_CONF_DEFAULT_HLS_STORAGE "disk"
57 #define SRS_CONF_DEFAULT_HLS_MOUNT "[vhost]/[app]/[stream].m3u8" 57 #define SRS_CONF_DEFAULT_HLS_MOUNT "[vhost]/[app]/[stream].m3u8"
58 #define SRS_CONF_DEFAULT_HLS_ACODEC "aac" 58 #define SRS_CONF_DEFAULT_HLS_ACODEC "aac"
  59 +#define SRS_CONF_DEFAULT_HLS_VCODEC "h264"
59 #define SRS_CONF_DEFAULT_DVR_PATH "./objs/nginx/html" 60 #define SRS_CONF_DEFAULT_DVR_PATH "./objs/nginx/html"
60 #define SRS_CONF_DEFAULT_DVR_PLAN_SESSION "session" 61 #define SRS_CONF_DEFAULT_DVR_PLAN_SESSION "session"
61 #define SRS_CONF_DEFAULT_DVR_PLAN_SEGMENT "segment" 62 #define SRS_CONF_DEFAULT_DVR_PLAN_SEGMENT "segment"
@@ -927,6 +928,10 @@ public: @@ -927,6 +928,10 @@ public:
927 * get the HLS default audio codec. 928 * get the HLS default audio codec.
928 */ 929 */
929 virtual std::string get_hls_acodec(std::string vhost); 930 virtual std::string get_hls_acodec(std::string vhost);
  931 + /**
  932 + * get the HLS default video codec.
  933 + */
  934 + virtual std::string get_hls_vcodec(std::string vhost);
930 // dvr section 935 // dvr section
931 private: 936 private:
932 /** 937 /**
@@ -131,14 +131,14 @@ string SrsHlsCacheWriter::cache() @@ -131,14 +131,14 @@ string SrsHlsCacheWriter::cache()
131 return data; 131 return data;
132 } 132 }
133 133
134 -SrsHlsSegment::SrsHlsSegment(bool write_cache, bool write_file, SrsCodecAudio ac) 134 +SrsHlsSegment::SrsHlsSegment(bool write_cache, bool write_file, SrsCodecAudio ac, SrsCodecVideo vc)
135 { 135 {
136 duration = 0; 136 duration = 0;
137 sequence_no = 0; 137 sequence_no = 0;
138 segment_start_dts = 0; 138 segment_start_dts = 0;
139 is_sequence_header = false; 139 is_sequence_header = false;
140 writer = new SrsHlsCacheWriter(write_cache, write_file); 140 writer = new SrsHlsCacheWriter(write_cache, write_file);
141 - muxer = new SrsTSMuxer(writer, ac); 141 + muxer = new SrsTSMuxer(writer, ac, vc);
142 } 142 }
143 143
144 SrsHlsSegment::~SrsHlsSegment() 144 SrsHlsSegment::~SrsHlsSegment()
@@ -246,19 +246,36 @@ int SrsHlsMuxer::segment_open(int64_t segment_start_dts) @@ -246,19 +246,36 @@ int SrsHlsMuxer::segment_open(int64_t segment_start_dts)
246 246
247 // load the default acodec from config. 247 // load the default acodec from config.
248 SrsCodecAudio default_acodec = SrsCodecAudioAAC; 248 SrsCodecAudio default_acodec = SrsCodecAudioAAC;
249 - std::string default_acodec_str = _srs_config->get_hls_acodec(req->vhost);  
250 - if (default_acodec_str == "mp3") {  
251 - default_acodec = SrsCodecAudioMP3;  
252 - srs_info("hls: use default mp3 acodec");  
253 - } else if (default_acodec_str == "aac") {  
254 - default_acodec = SrsCodecAudioAAC;  
255 - srs_info("hls: use default aac acodec");  
256 - } else {  
257 - srs_warn("hls: use aac for other codec=%s", default_acodec_str.c_str()); 249 + if (true) {
  250 + std::string default_acodec_str = _srs_config->get_hls_acodec(req->vhost);
  251 + if (default_acodec_str == "mp3") {
  252 + default_acodec = SrsCodecAudioMP3;
  253 + srs_info("hls: use default mp3 acodec");
  254 + } else if (default_acodec_str == "aac") {
  255 + default_acodec = SrsCodecAudioAAC;
  256 + srs_info("hls: use default aac acodec");
  257 + } else {
  258 + srs_warn("hls: use aac for other codec=%s", default_acodec_str.c_str());
  259 + }
  260 + }
  261 +
  262 + // load the default vcodec from config.
  263 + SrsCodecVideo default_vcodec = SrsCodecVideoAVC;
  264 + if (true) {
  265 + std::string default_vcodec_str = _srs_config->get_hls_vcodec(req->vhost);
  266 + if (default_vcodec_str == "h264") {
  267 + default_vcodec = SrsCodecVideoAVC;
  268 + srs_info("hls: use default h264 vcodec");
  269 + } else if (default_vcodec_str == "vn") {
  270 + default_vcodec = SrsCodecVideoDisabled;
  271 + srs_info("hls: use default vn vcodec for pure audio");
  272 + } else {
  273 + srs_warn("hls: use h264 for other codec=%s", default_vcodec_str.c_str());
  274 + }
258 } 275 }
259 276
260 // new segment. 277 // new segment.
261 - current = new SrsHlsSegment(should_write_cache, should_write_file, default_acodec); 278 + current = new SrsHlsSegment(should_write_cache, should_write_file, default_acodec, default_vcodec);
262 current->sequence_no = _sequence_no++; 279 current->sequence_no = _sequence_no++;
263 current->segment_start_dts = segment_start_dts; 280 current->segment_start_dts = segment_start_dts;
264 281
@@ -144,7 +144,7 @@ public: @@ -144,7 +144,7 @@ public:
144 // whether current segement is sequence header. 144 // whether current segement is sequence header.
145 bool is_sequence_header; 145 bool is_sequence_header;
146 public: 146 public:
147 - SrsHlsSegment(bool write_cache, bool write_file, SrsCodecAudio ac); 147 + SrsHlsSegment(bool write_cache, bool write_file, SrsCodecAudio ac, SrsCodecVideo vc);
148 virtual ~SrsHlsSegment(); 148 virtual ~SrsHlsSegment();
149 public: 149 public:
150 /** 150 /**
@@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 // current release version 31 // current release version
32 #define VERSION_MAJOR 2 32 #define VERSION_MAJOR 2
33 #define VERSION_MINOR 0 33 #define VERSION_MINOR 0
34 -#define VERSION_REVISION 117 34 +#define VERSION_REVISION 118
35 35
36 // server info. 36 // server info.
37 #define RTMP_SIG_SRS_KEY "SRS" 37 #define RTMP_SIG_SRS_KEY "SRS"
@@ -98,7 +98,10 @@ enum SrsCodecVideo @@ -98,7 +98,10 @@ enum SrsCodecVideo
98 // set to the zero to reserved, for array map. 98 // set to the zero to reserved, for array map.
99 SrsCodecVideoReserved = 0, 99 SrsCodecVideoReserved = 0,
100 SrsCodecVideoReserved1 = 1, 100 SrsCodecVideoReserved1 = 1,
101 - SrsCodecVideoReserved2 = 8, 101 + SrsCodecVideoReserved2 = 9,
  102 +
  103 + // for user to disable video, for example, use pure audio hls.
  104 + SrsCodecVideoDisabled = 8,
102 105
103 SrsCodecVideoSorensonH263 = 2, 106 SrsCodecVideoSorensonH263 = 2,
104 SrsCodecVideoScreenVideo = 3, 107 SrsCodecVideoScreenVideo = 3,
@@ -75,327 +75,6 @@ int aac_sample_rates[] = @@ -75,327 +75,6 @@ int aac_sample_rates[] =
75 7350, 0, 0, 0 75 7350, 0, 0, 0
76 }; 76 };
77 77
78 -// @see: ngx_rtmp_mpegts_header  
79 -u_int8_t mpegts_header[] = {  
80 - /* TS */  
81 - 0x47, 0x40, 0x00, 0x10, 0x00,  
82 - /* PSI */  
83 - 0x00, 0xb0, 0x0d, 0x00, 0x01, 0xc1, 0x00, 0x00,  
84 - /* PAT */  
85 - 0x00, 0x01, 0xf0, 0x01,  
86 - /* CRC */  
87 - 0x2e, 0x70, 0x19, 0x05,  
88 - /* stuffing 167 bytes */  
89 - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  
90 - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  
91 - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  
92 - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  
93 - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  
94 - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  
95 - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  
96 - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  
97 - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  
98 - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  
99 - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  
100 - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  
101 - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  
102 - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  
103 - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  
104 - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  
105 - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  
106 -  
107 - /* TS */  
108 - 0x47, 0x50, 0x01, 0x10, 0x00,  
109 - /* PSI */  
110 - 0x02, 0xb0, 0x17, 0x00, 0x01, 0xc1, 0x00, 0x00,  
111 - /* PMT */  
112 - 0xe1, 0x00,  
113 - 0xf0, 0x00,  
114 - // must generate header with/without video, @see:  
115 - // https://github.com/winlinvip/simple-rtmp-server/issues/40  
116 - 0x1b, 0xe1, 0x00, 0xf0, 0x00, /* h264, pid=0x100=256 */  
117 -};  
118 -u_int8_t mpegts_header_aac[] = {  
119 - 0x0f, 0xe1, 0x01, 0xf0, 0x00, /* aac, pid=0x101=257 */  
120 - /* CRC */  
121 - 0x2f, 0x44, 0xb9, 0x9b, /* crc for aac */  
122 -};  
123 -u_int8_t mpegts_header_mp3[] = {  
124 - 0x03, 0xe1, 0x01, 0xf0, 0x00, /* mp3 */  
125 - /* CRC */  
126 - 0x4e, 0x59, 0x3d, 0x1e, /* crc for mp3 */  
127 -};  
128 -u_int8_t mpegts_header_padding[] = {  
129 - /* stuffing 157 bytes */  
130 - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  
131 - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  
132 - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  
133 - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  
134 - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  
135 - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  
136 - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  
137 - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  
138 - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  
139 - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  
140 - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  
141 - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  
142 - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  
143 - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  
144 - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  
145 - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff  
146 -};  
147 -  
148 -// @see: ngx_rtmp_mpegts.c  
149 -// TODO: support full mpegts feature in future.  
150 -class SrsMpegtsWriter  
151 -{  
152 -public:  
153 - static int write_header(SrsFileWriter* writer, SrsCodecAudio acodec)  
154 - {  
155 - int ret = ERROR_SUCCESS;  
156 -  
157 - if ((ret = writer->write(mpegts_header, sizeof(mpegts_header), NULL)) != ERROR_SUCCESS) {  
158 - ret = ERROR_HLS_WRITE_FAILED;  
159 - srs_error("write ts file header failed. ret=%d", ret);  
160 - return ret;  
161 - }  
162 -  
163 - if (acodec == SrsCodecAudioAAC) {  
164 - if ((ret = writer->write(mpegts_header_aac, sizeof(mpegts_header_aac), NULL)) != ERROR_SUCCESS) {  
165 - ret = ERROR_HLS_WRITE_FAILED;  
166 - srs_error("write ts file aac header failed. ret=%d", ret);  
167 - return ret;  
168 - }  
169 - } else {  
170 - if ((ret = writer->write(mpegts_header_mp3, sizeof(mpegts_header_mp3), NULL)) != ERROR_SUCCESS) {  
171 - ret = ERROR_HLS_WRITE_FAILED;  
172 - srs_error("write ts file mp3 header failed. ret=%d", ret);  
173 - return ret;  
174 - }  
175 - }  
176 -  
177 - if ((ret = writer->write(mpegts_header_padding, sizeof(mpegts_header_padding), NULL)) != ERROR_SUCCESS) {  
178 - ret = ERROR_HLS_WRITE_FAILED;  
179 - srs_error("write ts file padding header failed. ret=%d", ret);  
180 - return ret;  
181 - }  
182 -  
183 - return ret;  
184 - }  
185 - static int write_frame(SrsFileWriter* writer, SrsMpegtsFrame* frame, SrsSimpleBuffer* buffer)  
186 - {  
187 - int ret = ERROR_SUCCESS;  
188 -  
189 - if (!buffer->bytes() || buffer->length() <= 0) {  
190 - return ret;  
191 - }  
192 -  
193 - char* last = buffer->bytes() + buffer->length();  
194 - char* pos = buffer->bytes();  
195 -  
196 - bool first = true;  
197 - while (pos < last) {  
198 - static char packet[188];  
199 - char* p = packet;  
200 -  
201 - frame->cc++;  
202 -  
203 - // sync_byte; //8bits  
204 - *p++ = 0x47;  
205 - // pid; //13bits  
206 - *p++ = (frame->pid >> 8) & 0x1f;  
207 - // payload_unit_start_indicator; //1bit  
208 - if (first) {  
209 - p[-1] |= 0x40;  
210 - }  
211 - *p++ = frame->pid;  
212 -  
213 - // transport_scrambling_control; //2bits  
214 - // adaption_field_control; //2bits, 0x01: PayloadOnly  
215 - // continuity_counter; //4bits  
216 - *p++ = 0x10 | (frame->cc & 0x0f);  
217 -  
218 - if (first) {  
219 - first = false;  
220 - if (frame->write_pcr) {  
221 - p[-1] |= 0x20; // Both Adaption and Payload  
222 - *p++ = 7; // size  
223 - *p++ = 0x50; // random access + PCR  
224 - // @see https://github.com/winlinvip/simple-rtmp-server/issues/311  
225 - p = write_pcr(p, frame->dts);  
226 - }  
227 -  
228 - // PES header  
229 - // packet_start_code_prefix; //24bits, '00 00 01'  
230 - *p++ = 0x00;  
231 - *p++ = 0x00;  
232 - *p++ = 0x01;  
233 - //8bits  
234 - *p++ = frame->sid;  
235 -  
236 - // pts(33bits) need 5bytes.  
237 - u_int8_t header_size = 5;  
238 - u_int8_t flags = 0x80; // pts  
239 -  
240 - // dts(33bits) need 5bytes also  
241 - if (frame->dts != frame->pts) {  
242 - header_size += 5;  
243 - flags |= 0x40; // dts  
244 - }  
245 -  
246 - // 3bytes: flag fields from PES_packet_length to PES_header_data_length  
247 - int pes_size = (last - pos) + header_size + 3;  
248 - if (pes_size > 0xffff) {  
249 - /**  
250 - * when actual packet length > 0xffff(65535),  
251 - * which exceed the max u_int16_t packet length,  
252 - * use 0 packet length, the next unit start indicates the end of packet.  
253 - */  
254 - pes_size = 0;  
255 - }  
256 -  
257 - // PES_packet_length; //16bits  
258 - *p++ = (pes_size >> 8);  
259 - *p++ = pes_size;  
260 -  
261 - // PES_scrambling_control; //2bits, '10'  
262 - // PES_priority; //1bit  
263 - // data_alignment_indicator; //1bit  
264 - // copyright; //1bit  
265 - // original_or_copy; //1bit  
266 - *p++ = 0x80; /* H222 */  
267 -  
268 - // PTS_DTS_flags; //2bits  
269 - // ESCR_flag; //1bit  
270 - // ES_rate_flag; //1bit  
271 - // DSM_trick_mode_flag; //1bit  
272 - // additional_copy_info_flag; //1bit  
273 - // PES_CRC_flag; //1bit  
274 - // PES_extension_flag; //1bit  
275 - *p++ = flags;  
276 -  
277 - // PES_header_data_length; //8bits  
278 - *p++ = header_size;  
279 -  
280 - // pts; // 33bits  
281 - p = write_dts_pts(p, flags >> 6, frame->pts);  
282 -  
283 - // dts; // 33bits  
284 - if (frame->dts != frame->pts) {  
285 - p = write_dts_pts(p, 1, frame->dts);  
286 - }  
287 - }  
288 -  
289 - int body_size = sizeof(packet) - (p - packet);  
290 - int in_size = last - pos;  
291 -  
292 - if (body_size <= in_size) {  
293 - memcpy(p, pos, body_size);  
294 - pos += body_size;  
295 - } else {  
296 - p = fill_stuff(p, packet, body_size, in_size);  
297 - memcpy(p, pos, in_size);  
298 - pos = last;  
299 - }  
300 -  
301 - // write ts packet  
302 - if ((ret = writer->write(packet, sizeof(packet), NULL)) != ERROR_SUCCESS) {  
303 - if (!srs_is_client_gracefully_close(ret)) {  
304 - srs_error("write ts file failed. ret=%d", ret);  
305 - }  
306 - return ret;  
307 - }  
308 - }  
309 -  
310 - return ret;  
311 - }  
312 -private:  
313 - static char* fill_stuff(char* pes_body_end, char* packet, int body_size, int in_size)  
314 - {  
315 - char* p = pes_body_end;  
316 -  
317 - // insert the stuff bytes before PES body  
318 - int stuff_size = (body_size - in_size);  
319 -  
320 - // adaption_field_control; //2bits  
321 - if (packet[3] & 0x20) {  
322 - // has adaptation  
323 - // packet[4]: adaption_field_length  
324 - // packet[5]: adaption field data  
325 - // base: start of PES body  
326 - char* base = &packet[5] + packet[4];  
327 - int len = p - base;  
328 - p = (char*)memmove(base + stuff_size, base, len) + len;  
329 - // increase the adaption field size.  
330 - packet[4] += stuff_size;  
331 -  
332 - return p;  
333 - }  
334 -  
335 - // create adaption field.  
336 - // adaption_field_control; //2bits  
337 - packet[3] |= 0x20;  
338 - // base: start of PES body  
339 - char* base = &packet[4];  
340 - int len = p - base;  
341 - p = (char*)memmove(base + stuff_size, base, len) + len;  
342 - // adaption_field_length; //8bits  
343 - packet[4] = (stuff_size - 1);  
344 - if (stuff_size >= 2) {  
345 - // adaption field flags.  
346 - packet[5] = 0;  
347 - // adaption data.  
348 - if (stuff_size > 2) {  
349 - memset(&packet[6], 0xff, stuff_size - 2);  
350 - }  
351 - }  
352 -  
353 - return p;  
354 - }  
355 - static char* write_pcr(char* p, int64_t pcr)  
356 - {  
357 - // the pcr=dts-delay, where dts = frame->dts + delay  
358 - // and the pcr should never be negative  
359 - // @see https://github.com/winlinvip/simple-rtmp-server/issues/268  
360 - srs_assert(pcr >= 0);  
361 -  
362 - int64_t v = pcr;  
363 -  
364 - *p++ = (char) (v >> 25);  
365 - *p++ = (char) (v >> 17);  
366 - *p++ = (char) (v >> 9);  
367 - *p++ = (char) (v >> 1);  
368 - *p++ = (char) (v << 7 | 0x7e);  
369 - *p++ = 0;  
370 -  
371 - return p;  
372 - }  
373 - static char* write_dts_pts(char* p, u_int8_t fb, int64_t pts)  
374 - {  
375 - int32_t val;  
376 -  
377 - val = fb << 4 | (((pts >> 30) & 0x07) << 1) | 1;  
378 - *p++ = val;  
379 -  
380 - val = (((pts >> 15) & 0x7fff) << 1) | 1;  
381 - *p++ = (val >> 8);  
382 - *p++ = val;  
383 -  
384 - val = (((pts) & 0x7fff) << 1) | 1;  
385 - *p++ = (val >> 8);  
386 - *p++ = val;  
387 -  
388 - return p;  
389 - }  
390 -};  
391 -  
392 -SrsMpegtsFrame::SrsMpegtsFrame()  
393 -{  
394 - pts = dts = 0;  
395 - pid = sid = cc = 0;  
396 - write_pcr = false;  
397 -}  
398 -  
399 string srs_ts_stream2string(SrsTsStream stream) 78 string srs_ts_stream2string(SrsTsStream stream)
400 { 79 {
401 switch (stream) { 80 switch (stream) {
@@ -600,6 +279,7 @@ int SrsTsContext::encode(SrsFileWriter* writer, SrsTsMessage* msg, SrsCodecVideo @@ -600,6 +279,7 @@ int SrsTsContext::encode(SrsFileWriter* writer, SrsTsMessage* msg, SrsCodecVideo
600 case SrsCodecVideoReserved: 279 case SrsCodecVideoReserved:
601 case SrsCodecVideoReserved1: 280 case SrsCodecVideoReserved1:
602 case SrsCodecVideoReserved2: 281 case SrsCodecVideoReserved2:
  282 + case SrsCodecVideoDisabled:
603 case SrsCodecVideoSorensonH263: 283 case SrsCodecVideoSorensonH263:
604 case SrsCodecVideoScreenVideo: 284 case SrsCodecVideoScreenVideo:
605 case SrsCodecVideoOn2VP6: 285 case SrsCodecVideoOn2VP6:
@@ -645,9 +325,9 @@ int SrsTsContext::encode(SrsFileWriter* writer, SrsTsMessage* msg, SrsCodecVideo @@ -645,9 +325,9 @@ int SrsTsContext::encode(SrsFileWriter* writer, SrsTsMessage* msg, SrsCodecVideo
645 325
646 // encode the media frame to PES packets over TS. 326 // encode the media frame to PES packets over TS.
647 if (msg->is_audio()) { 327 if (msg->is_audio()) {
648 - return encode_pes(writer, msg, audio_pid, as); 328 + return encode_pes(writer, msg, audio_pid, as, vs == SrsTsStreamReserved);
649 } else { 329 } else {
650 - return encode_pes(writer, msg, video_pid, vs); 330 + return encode_pes(writer, msg, video_pid, vs, vs == SrsTsStreamReserved);
651 } 331 }
652 } 332 }
653 333
@@ -711,7 +391,7 @@ int SrsTsContext::encode_pat_pmt(SrsFileWriter* writer, int16_t vpid, SrsTsStrea @@ -711,7 +391,7 @@ int SrsTsContext::encode_pat_pmt(SrsFileWriter* writer, int16_t vpid, SrsTsStrea
711 return ret; 391 return ret;
712 } 392 }
713 393
714 -int SrsTsContext::encode_pes(SrsFileWriter* writer, SrsTsMessage* msg, int16_t pid, SrsTsStream sid) 394 +int SrsTsContext::encode_pes(SrsFileWriter* writer, SrsTsMessage* msg, int16_t pid, SrsTsStream sid, bool pure_audio)
715 { 395 {
716 int ret = ERROR_SUCCESS; 396 int ret = ERROR_SUCCESS;
717 397
@@ -719,6 +399,11 @@ int SrsTsContext::encode_pes(SrsFileWriter* writer, SrsTsMessage* msg, int16_t p @@ -719,6 +399,11 @@ int SrsTsContext::encode_pes(SrsFileWriter* writer, SrsTsMessage* msg, int16_t p
719 return ret; 399 return ret;
720 } 400 }
721 401
  402 + if (sid != SrsTsStreamVideoH264 && sid != SrsTsStreamAudioMp3 && sid != SrsTsStreamAudioAAC) {
  403 + srs_info("ts: ignore the unknown stream, sid=%d", sid);
  404 + return ret;
  405 + }
  406 +
722 SrsTsChannel* channel = get(pid); 407 SrsTsChannel* channel = get(pid);
723 srs_assert(channel); 408 srs_assert(channel);
724 409
@@ -729,9 +414,15 @@ int SrsTsContext::encode_pes(SrsFileWriter* writer, SrsTsMessage* msg, int16_t p @@ -729,9 +414,15 @@ int SrsTsContext::encode_pes(SrsFileWriter* writer, SrsTsMessage* msg, int16_t p
729 while (p < end) { 414 while (p < end) {
730 SrsTsPacket* pkt = NULL; 415 SrsTsPacket* pkt = NULL;
731 if (p == start) { 416 if (p == start) {
  417 + // for pure audio stream, always write pcr.
  418 + bool write_pcr = msg->write_pcr;
  419 + if (pure_audio && msg->is_audio()) {
  420 + write_pcr = true;
  421 + }
  422 +
732 pkt = SrsTsPacket::create_pes_first(this, 423 pkt = SrsTsPacket::create_pes_first(this,
733 pid, msg->sid, channel->continuity_counter++, msg->discontinuity, 424 pid, msg->sid, channel->continuity_counter++, msg->discontinuity,
734 - msg->write_pcr? msg->dts:-1, msg->dts, msg->pts, msg->payload->length() 425 + write_pcr? msg->dts:-1, msg->dts, msg->pts, msg->payload->length()
735 ); 426 );
736 } else { 427 } else {
737 pkt = SrsTsPacket::create_pes_continue(this, 428 pkt = SrsTsPacket::create_pes_continue(this,
@@ -1030,9 +721,13 @@ SrsTsPacket* SrsTsPacket::create_pmt(SrsTsContext* context, int16_t pmt_number, @@ -1030,9 +721,13 @@ SrsTsPacket* SrsTsPacket::create_pmt(SrsTsContext* context, int16_t pmt_number,
1030 pmt->current_next_indicator = 1; 721 pmt->current_next_indicator = 1;
1031 pmt->section_number = 0; 722 pmt->section_number = 0;
1032 pmt->last_section_number = 0; 723 pmt->last_section_number = 0;
1033 - pmt->PCR_PID = vpid;  
1034 pmt->program_info_length = 0; 724 pmt->program_info_length = 0;
1035 - pmt->infos.push_back(new SrsTsPayloadPMTESInfo(vs, vpid)); 725 + if (vs == SrsTsStreamVideoH264) {
  726 + pmt->PCR_PID = vpid;
  727 + pmt->infos.push_back(new SrsTsPayloadPMTESInfo(vs, vpid));
  728 + } else {
  729 + pmt->PCR_PID = apid;
  730 + }
1036 pmt->infos.push_back(new SrsTsPayloadPMTESInfo(as, apid)); 731 pmt->infos.push_back(new SrsTsPayloadPMTESInfo(as, apid));
1037 pmt->CRC_32 = 0; // calc in encode. 732 pmt->CRC_32 = 0; // calc in encode.
1038 return pkt; 733 return pkt;
@@ -2916,14 +2611,13 @@ int SrsTsPayloadPMT::psi_encode(SrsStream* stream) @@ -2916,14 +2611,13 @@ int SrsTsPayloadPMT::psi_encode(SrsStream* stream)
2916 return ret; 2611 return ret;
2917 } 2612 }
2918 2613
2919 -SrsTSMuxer::SrsTSMuxer(SrsFileWriter* w, SrsCodecAudio ac) 2614 +SrsTSMuxer::SrsTSMuxer(SrsFileWriter* w, SrsCodecAudio ac, SrsCodecVideo vc)
2920 { 2615 {
2921 writer = w; 2616 writer = w;
2922 context = NULL; 2617 context = NULL;
2923 2618
2924 acodec = ac; 2619 acodec = ac;
2925 - // default to avc(h.264)  
2926 - vcodec = SrsCodecVideoAVC; 2620 + vcodec = vc;
2927 } 2621 }
2928 2622
2929 SrsTSMuxer::~SrsTSMuxer() 2623 SrsTSMuxer::~SrsTSMuxer()
@@ -3295,7 +2989,7 @@ int SrsTsEncoder::initialize(SrsFileWriter* fs) @@ -3295,7 +2989,7 @@ int SrsTsEncoder::initialize(SrsFileWriter* fs)
3295 _fs = fs; 2989 _fs = fs;
3296 2990
3297 srs_freep(muxer); 2991 srs_freep(muxer);
3298 - muxer = new SrsTSMuxer(fs, SrsCodecAudioAAC); 2992 + muxer = new SrsTSMuxer(fs, SrsCodecAudioAAC, SrsCodecVideoAVC);
3299 2993
3300 if ((ret = muxer->open("")) != ERROR_SUCCESS) { 2994 if ((ret = muxer->open("")) != ERROR_SUCCESS) {
3301 return ret; 2995 return ret;
@@ -51,20 +51,6 @@ class SrsTsPacket; @@ -51,20 +51,6 @@ class SrsTsPacket;
51 // Transport Stream packets are 188 bytes in length. 51 // Transport Stream packets are 188 bytes in length.
52 #define SRS_TS_PACKET_SIZE 188 52 #define SRS_TS_PACKET_SIZE 188
53 53
54 -// @see: ngx_rtmp_SrsMpegtsFrame_t  
55 -class SrsMpegtsFrame  
56 -{  
57 -public:  
58 - int64_t pts;  
59 - int64_t dts;  
60 - int pid;  
61 - int sid;  
62 - int cc; // continuity_counter  
63 - bool write_pcr;  
64 -  
65 - SrsMpegtsFrame();  
66 -};  
67 -  
68 /** 54 /**
69 * the pid of ts packet, 55 * the pid of ts packet,
70 * Table 2-3 - PID table, hls-mpeg-ts-iso13818-1.pdf, page 37 56 * Table 2-3 - PID table, hls-mpeg-ts-iso13818-1.pdf, page 37
@@ -387,7 +373,7 @@ public: @@ -387,7 +373,7 @@ public:
387 virtual int encode(SrsFileWriter* writer, SrsTsMessage* msg, SrsCodecVideo vc, SrsCodecAudio ac); 373 virtual int encode(SrsFileWriter* writer, SrsTsMessage* msg, SrsCodecVideo vc, SrsCodecAudio ac);
388 private: 374 private:
389 virtual int encode_pat_pmt(SrsFileWriter* writer, int16_t vpid, SrsTsStream vs, int16_t apid, SrsTsStream as); 375 virtual int encode_pat_pmt(SrsFileWriter* writer, int16_t vpid, SrsTsStream vs, int16_t apid, SrsTsStream as);
390 - virtual int encode_pes(SrsFileWriter* writer, SrsTsMessage* msg, int16_t pid, SrsTsStream sid); 376 + virtual int encode_pes(SrsFileWriter* writer, SrsTsMessage* msg, int16_t pid, SrsTsStream sid, bool pure_audio);
391 }; 377 };
392 378
393 /** 379 /**
@@ -1547,7 +1533,7 @@ private: @@ -1547,7 +1533,7 @@ private:
1547 SrsFileWriter* writer; 1533 SrsFileWriter* writer;
1548 std::string path; 1534 std::string path;
1549 public: 1535 public:
1550 - SrsTSMuxer(SrsFileWriter* w, SrsCodecAudio ac); 1536 + SrsTSMuxer(SrsFileWriter* w, SrsCodecAudio ac, SrsCodecVideo vc);
1551 virtual ~SrsTSMuxer(); 1537 virtual ~SrsTSMuxer();
1552 public: 1538 public:
1553 /** 1539 /**