winlin

support pure audio hls. change to 0.9.24

... ... @@ -44,7 +44,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <srs_app_pithy_print.hpp>
// max PES packets size to flush the video.
#define SRS_HLS_AUDIO_CACHE_SIZE 512 * 1024
#define SRS_HLS_AUDIO_CACHE_SIZE 1024 * 1024
// @see: NGX_RTMP_HLS_DELAY,
// 63000: 700ms, ts_tbn=90000
... ... @@ -481,12 +481,20 @@ SrsHlsSegment::~SrsHlsSegment()
srs_freep(muxer);
}
double SrsHlsSegment::update_duration(int64_t current_frame_dts)
void SrsHlsSegment::update_duration(int64_t current_frame_dts)
{
// we use video/audio to update segment duration,
// so when reap segment, some previous audio frame will
// update the segment duration, which is nagetive,
// just ignore it.
if (current_frame_dts < segment_start_dts) {
return;
}
duration = (current_frame_dts - segment_start_dts) / 90000.0;
srs_assert(duration >= 0);
return duration;
return;
}
SrsHlsAacJitter::SrsHlsAacJitter()
... ... @@ -503,7 +511,6 @@ SrsHlsMuxer::SrsHlsMuxer()
hls_fragment = hls_window = 0;
file_index = 0;
current = NULL;
video_count = 0;
}
SrsHlsMuxer::~SrsHlsMuxer()
... ... @@ -542,9 +549,6 @@ int SrsHlsMuxer::segment_open(int64_t segment_start_dts)
return ret;
}
// reset video count for new publish session.
video_count = 0;
// TODO: create all parents dirs.
// create dir for app.
if ((ret = create_dir()) != ERROR_SUCCESS) {
... ... @@ -605,6 +609,9 @@ int SrsHlsMuxer::flush_audio(SrsMpegtsFrame* af, SrsCodecBuffer* ab)
return ret;
}
// update the duration of segment.
current->update_duration(af->pts);
if ((ret = current->muxer->write_audio(af, ab)) != ERROR_SUCCESS) {
return ret;
}
... ... @@ -635,6 +642,9 @@ int SrsHlsMuxer::flush_video(
return ret;
}
// write success, clear and free the buffer
vb->free();
return ret;
}
... ... @@ -860,6 +870,8 @@ SrsHlsCache::SrsHlsCache()
af = new SrsMpegtsFrame();
vf = new SrsMpegtsFrame();
video_count = 0;
}
SrsHlsCache::~SrsHlsCache()
... ... @@ -890,6 +902,9 @@ int SrsHlsCache::on_publish(SrsHlsMuxer* muxer, SrsRequest* req, int64_t segment
// get the hls path config
std::string hls_path = _srs_config->get_hls_path(vhost);
// reset video count for new publish session.
video_count = 0;
// open muxer
if ((ret = muxer->update_config(app, stream, hls_path, hls_fragment, hls_window)) != ERROR_SUCCESS) {
srs_error("m3u8 muxer update config failed. ret=%d", ret);
... ... @@ -956,13 +971,25 @@ int SrsHlsCache::write_audio(SrsCodec* codec, SrsHlsMuxer* muxer, int64_t pts, S
}
}
// for pure audio
// start new segment when duration overflow.
if (video_count == 0 && muxer->is_segment_overflow()) {
srs_trace("pure audio segment reap");
if ((ret = reap_segment(muxer, af->pts)) != ERROR_SUCCESS) {
return ret;
}
}
return ret;
}
int SrsHlsCache::write_video(SrsCodec* codec, SrsHlsMuxer* muxer, int64_t dts, SrsCodecSample* sample)
int SrsHlsCache::write_video(
SrsCodec* codec, SrsHlsMuxer* muxer, int64_t dts, SrsCodecSample* sample)
{
int ret = ERROR_SUCCESS;
video_count++;
// write video to cache.
if ((ret = cache_video(codec, sample)) != ERROR_SUCCESS) {
return ret;
... ... @@ -974,26 +1001,11 @@ int SrsHlsCache::write_video(SrsCodec* codec, SrsHlsMuxer* muxer, int64_t dts, S
vf->sid = TS_VIDEO_AVC;
vf->key = sample->frame_type == SrsCodecVideoAVCFrameKeyFrame;
// reopen the muxer for a gop
// close current segment, open a new segment,
// then write the key frame to the new segment.
// new segment when:
// 1. base on gop.
// 2. some gops duration overflow.
if (vf->key && muxer->is_segment_overflow()) {
if ((ret = muxer->segment_close()) != ERROR_SUCCESS) {
srs_error("m3u8 muxer close segment failed. ret=%d", ret);
return ret;
}
if ((ret = muxer->segment_open(vf->dts)) != ERROR_SUCCESS) {
srs_error("m3u8 muxer open segment failed. ret=%d", ret);
return ret;
}
// TODO: flush audio before or after segment?
// segment open, flush the audio.
// @see: ngx_rtmp_hls_open_fragment
/* start fragment with audio to make iPhone happy */
if ((ret = muxer->flush_audio(af, ab)) != ERROR_SUCCESS) {
srs_error("m3u8 muxer flush audio failed. ret=%d", ret);
if ((ret = reap_segment(muxer, vf->dts)) != ERROR_SUCCESS) {
return ret;
}
}
... ... @@ -1004,8 +1016,31 @@ int SrsHlsCache::write_video(SrsCodec* codec, SrsHlsMuxer* muxer, int64_t dts, S
return ret;
}
// write success, clear and free the buffer
vb->free();
return ret;
}
int SrsHlsCache::reap_segment(SrsHlsMuxer* muxer, int64_t segment_start_dts)
{
int ret = ERROR_SUCCESS;
if ((ret = muxer->segment_close()) != ERROR_SUCCESS) {
srs_error("m3u8 muxer close segment failed. ret=%d", ret);
return ret;
}
if ((ret = muxer->segment_open(segment_start_dts)) != ERROR_SUCCESS) {
srs_error("m3u8 muxer open segment failed. ret=%d", ret);
return ret;
}
// TODO: flush audio before or after segment?
// segment open, flush the audio.
// @see: ngx_rtmp_hls_open_fragment
/* start fragment with audio to make iPhone happy */
if ((ret = muxer->flush_audio(af, ab)) != ERROR_SUCCESS) {
srs_error("m3u8 muxer flush audio failed. ret=%d", ret);
return ret;
}
return ret;
}
... ...
... ... @@ -124,7 +124,7 @@ public:
* update the segment duration.
* @current_frame_dts the dts of frame, in tbn of ts.
*/
virtual double update_duration(int64_t current_frame_dts);
virtual void update_duration(int64_t current_frame_dts);
};
/**
... ... @@ -149,14 +149,6 @@ private:
std::string m3u8;
private:
/**
* for pure audio HLS application,
* the video count used to count the video,
* if zero and audio buffer overflow, reap the ts,
* just like we got a keyframe.
*/
u_int32_t video_count;
private:
/**
* m3u8 segments.
*/
std::vector<SrsHlsSegment*> segments;
... ... @@ -219,6 +211,14 @@ private:
int64_t audio_buffer_start_pts;
// time jitter for aac
SrsHlsAacJitter* aac_jitter;
private:
/**
* for pure audio HLS application,
* the video count used to count the video,
* if zero and audio buffer overflow, reap the ts,
* just like we got a keyframe.
*/
u_int32_t video_count;
public:
SrsHlsCache();
virtual ~SrsHlsCache();
... ... @@ -237,6 +237,13 @@ public:
*/
virtual int write_video(SrsCodec* codec, SrsHlsMuxer* muxer, int64_t dts, SrsCodecSample* sample);
private:
/**
* reopen the muxer for a new hls segment,
* close current segment, open a new segment,
* then write the key frame to the new segment.
* so, user must reap_segment then flush_video to hls muxer.
*/
virtual int reap_segment(SrsHlsMuxer* muxer, int64_t segment_start_dts);
virtual int cache_audio(SrsCodec* codec, SrsCodecSample* sample);
virtual int cache_video(SrsCodec* codec, SrsCodecSample* sample);
};
... ...
... ... @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// current release version
#define VERSION_MAJOR "0"
#define VERSION_MINOR "9"
#define VERSION_REVISION "23"
#define VERSION_REVISION "24"
#define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION
// server info.
#define RTMP_SIG_SRS_KEY "srs"
... ...