SRS Srshlscache::reap_segment Detailed

Source: Internet
Author: User
Tags tmp file

1. Is it possible to slice the detection

First, when calling the Srshlscache::reap_segment function for slicing, there is a function for audio or video to detect whether the length of the current slice meets the required length.

For audio, the Srshlsmuxer::is_segment_absolutely_overflow function is called for detection, as follows:

bool SrsHlsMuxer::is_segment_absolutely_overflow(){    srs_assert(current);        /* 若当前片的时长小于 200 ms,则直接返回 false,即不允许切片 */    /* to prevent very small segment. */    if (current->duration * 1000 <         2 * SRS_AUTO_HLS_SEGMENT_MIN_DURATION_MS) {        return false;    }        /* 若没有配置 hls_ts_floor,则默认为 0 */    /* use N% deviation, to smoother. */    double deviation = hls_ts_floor ?         SRS_HLS_FLOOR_REAP_PERCENT * deviation_ts * hls_fragment : 0.0;        /* hls_aof_ratio 默认为 2.0, 而 hls_fragment 默认为 10s,     * 则需要当前片的时长大于 20s 时,才会进行切片 */    return current->duration >= hls_aof_ratio * hls_fragment + deviation;}

For video, the Srshlsmuxer::is_segment_overflow function is called for detection, as follows:

bool SrsHlsMuxer::is_segment_overflow(){    srs_assert(current);        /* 同样,若小于 200ms,直接不允许切片 */    /* to prevent very small segment. */    if (current->duration * 1000 <         2 * SRS_AUTO_HLS_SEGMENT_MIN_DURATION_MS) {        return false;    }        /* use N% deviation, to smoother. */    double deviation = hls_ts_floor?         SRS_HLS_FLOOR_REAP_PERCENT * deviation_ts * hls_fragment : 0.0;        /* 假设 hls_fragment 配置为 10s,因此若当前片的时长     * 大于 10s 即可进行切片 */    return current->duration >= hls_fragment + deviation;}
    • When the above two functions are called, the Srshlscache::reap_segment function is called to slice the current slice when it detects that one is satisfied.
2. Srshlscache::reap_segment
/* * Reopen the muxer for a new HLS segment, * Close current segment, open a new segment, * then write the key frame to th e new segment. * So, the user must reap_segment then flush_video to HLS muxer. */int srshlscache::reap_segment (String log_desc, srshlsmuxer* muxer, int64_t segment_start_dts) {int ret = ERROR_SU        ccess;     /* Todo:flush audio before or after segment? * Todo:fresh segment begin with audio or video? */* Close current TS. */* The function constructs a m3u8 file that updates all TS files that are currently compliant with the duration to the Playlist list of the file so that the client can play * and also releases all resources for the current slice (that is, present) * * IF (ret = Muxer->segment_close (LOG_DESC))! = ERROR_SUCCESS) {Srs_error ("m3u8 muxer close segment failed.        ret=%d ", ret);    return ret; }/* Open new TS. */if (ret = Muxer->segment_open (SEGMENT_START_DTS))! = ERROR_SUCCESS) {srs_error ("m3u8 muxer open segment Failed.        ret=%d ", ret);    return ret; }/* Segment open, flush video first. */if (ret = muxer->Flush_video (cache))! = ERROR_SUCCESS) {srs_error ("m3u8 muxer flush video failed.        ret=%d ", ret);    return ret;     }/* Segment open, flush the audio. * @see: Ngx_rtmp_hls_open_fragment * Start fragment with audio to make IPhone happy */if (ret = muxer->flush_a Udio (cache))! = ERROR_SUCCESS) {srs_error ("m3u8 muxer flush audio failed.        ret=%d ", ret);    return ret; } return ret;}
    • First call the Srshlsmuxer::segment_close function to close the current TS.
3. Srshlsmuxer::segment_close
/** * Close Segment (TS). * @param log_desc the description for log.        */int srshlsmuxer::segment_close (string log_desc) {int ret = ERROR_SUCCESS;        if (!current) {Srs_warn ("ignore the segment close, for segment are not open.");    return ret; }/* When close current segment, the current segment * must is not NULL.        */Srs_assert (current); /* Assert segment duplicate.    */Std::vector<srshlssegment*>::iterator it;    it = Std::find (Segments.begin (), Segments.end (), current);        Srs_assert (it = = Segments.end ());     /* Valid, add to segments if segment duration are OK * When too small, it maybe not enough data to play.     * When too large, it maybe timestamp corrupt. * Make the segment more acceptable, when in [Min, MAX_TD * 2], it's OK */if (current->duration * + >= Srs_aut  O_hls_segment_min_duration_ms && (int) current->duration <= MAX_TD * 2) {/* If the current slice can be sliced, save the slice to   Segments Vector container      * SEGMENTS:M3U8 Segments */segments.push_back (current); /* Here the two calls are temporarily ignored/////* Use async-to-Call of the HTTP hooks, for it'll cause thread switch. */if (ret = Async->execute (New Srsdvrasynccallonhls (_srs_context->get_id (), req, CU Rrent->full_path, Current->uri, m3u8, M3u8_url, Current->sequence_no, current->duration))! = ERRO        r_success) {return ret; }/* Use async-to-call the HTTP hooks, for it'll cause thread switch. */if (ret = Async->execute (New Srsdvrasynccallonhlsnotify (_srs_context->get_id (), req, current-        >uri)))! = ERROR_SUCCESS) {return ret; }/* Close the muxer of finished segment.        */Srs_freep (current->muxer);        /* Full_path:./objs/nginx/html/live/livestream-0.ts */std::string Full_path = current->full_path;                current = NULL; /* RENAME from TMP to Real path */std::string tmp_file = Full_path + ". tmp"; /* Rename the./objs/nginx/html/live/livestream-0.ts.tmp file to *./objs/nginx/html/live/livestream-0.ts */if (sho            Uld_write_file && Rename (Tmp_file.c_str (), Full_path.c_str ()) < 0) {ret = error_hls_write_failed; Srs_error ("Rename TS file failed,%s =%s. ret=%d", Tmp_file.c_str (), Full_path.c_str (), ret            );        return ret;                }} else {/* reuse current segment index. */_sequence_no--;        /* Rename from TMP to real path */std::string tmp_file = Current->full_path + ". tmp"; if (should_write_file) {if (unlink (TMP_FILE.C_STR ()) < 0) {Srs_warn ("Ignore unlink path FAI            LED, file=%s. ", Tmp_file.c_str ());    }} srs_freep (current);     }/* The segments to remove */std::vector<srshlssegment*> segment_to_remove;   /* Shrink the segments.    */Double duration = 0;    int remove_index =-1;        for (int i = (int) segments.size ()-1; I >= 0; i--) {srshlssegment* segment = Segments[i];                /* Count the total length of all sliced slices saved by segmtns container */duration + = segment->duration; /* If the total length of all slices exceeds the HLS window size limit, * Discards the first slice in the first m3u8 until the total length of the TS * is within this configuration item range.            */if ((int) duration > Hls_window) {/* Record the current number of slices to be removed */remove_index = i;        Break }///segments Remove_index before traversing the segments container, removing the first remove_index slices from the "*/for" (int i = 0; i < remove_ Index &&!segments.empty ();        i++) {srshlssegment* segment = *segments.begin ();        Segments.erase (Segments.begin ());    /* Save all removed slices temporarily in the container */Segment_ro_remove.push_back (segment);        }/* Refresh the m3u8, donot contains the removed TS */ret = refresh_m3u8 (); /* Remove the TS file. */for (int i = 0; i < (int) segment_to_remove.size ();                i++) {srshlssegment* segment = Segment_to_remove[i]; /* Remove the TS file from disk */if (Hls_cleanup && should_write_file) {if (Unlink (segment->full_path.c_s            TR ()) < 0) {Srs_warn ("Cleanup unlink path failed, file=%s.", Segment->full_path.c_str ());    }} srs_freep (segment);        } segment_to_remove.clear (); /* check ret of refresh m3u8 */if (ret! = ERROR_SUCCESS) {srs_error ("Refresh m3u8 failed.        ret=%d ", ret);    return ret; } return ret;}
    • The function first saves the slice that satisfies the time length to the segments vector container, and then checks whether the total length of all slices in the current segments has exceeded the Hls_window limit, which defaults to 60s. If the limit is exceeded, the first slice in the first m3u8 is discarded until the total length of the TS is within the range of this configuration item. Then call the srshlsmuxer::refresh_m3u8 function to refresh the m3u8 and no longer contain the slices that have just been deleted.
3.1 srshlsmuxer::refresh_m3u8
int SrsHlsMuxer::refresh_m3u8(){    int ret = ERROR_SUCCESS;        /* no segments, also no m3u8, return. */    if (segments.size() == 0) {        return ret;    }        std::string temp_m3u8 = m3u8 + ".temp";    if ((ret = _refresh_m3u8(temp_m3u8)) == ERROR_SUCCESS) {        /* 将该临时文件 livestream.m3u8.temp 重命名为 livestream.m3u8 */        if (should_write_file && rename(temp_m3u8.c_str(), m3u8.c_str()) < 0) {            ret = ERROR_HLS_WRITE_FAILED;            srs_error("rename m3u8 file failed. %s => %s, ret=%d", temp_m3u8.c_str(), m3u8.c_str(), ret);        }    }        /* remove the temp file. */    if (srs_path_exists(temp_m3u8)) {        /* 若该临时文件存在则删除该临时文件 */        if (unlink(temp_m3u8.c_str()) < 0) {            srs_warn("ignore remove m3u8 failed, %s", temp_m3u8.c_str());        }    }        return ret;}
    • The function first generates an absolute path to the m3u8 file, and then calls the SRSHLSMUXER::_REFRESH_M3U8 function based on that path.
3.2 srshlsmuxer::_refresh_m3u8
int srshlsmuxer::_refresh_m3u8 (string m3u8_file) {int ret = ERROR_SUCCESS; /* No segments, return.    */if (segments.size () = = 0) {return ret;    } srshlscachewriter writer (should_write_cache, should_write_file); if (ret = Writer.open (m3u8_file))! = ERROR_SUCCESS) {srs_error ("Open m3u8 file%s failed.        ret=%d ", M3u8_file.c_str (), ret);    return ret;    }/* #EXTM3U \ n * #EXT-x-version:3\n * #EXT-x-allow-cache:yes\n */Std::stringstream SS; SS << "#EXTM3U" << srs_consts_lf << "#EXT-x-version:3" << srs_consts_lf << "#EXT        -x-allow-cache:yes "<< srs_consts_lf;    /* #EXT-x-media-sequence:4294967295\n */srshlssegment* first = *segments.begin ();        SS << "#EXT-x-media-sequence:" << first->sequence_no << srs_consts_lf; /* Iterator shared for TD generation and segments wrote.        */Std::vector<srshlssegment*>::iterator it; /* #EXT-x-targetduration:4294967295\n */* * @see hls-m3u8-draft-pantos-http-live-streaming-12.pdf, page * The Media     Playlist file must contain an ext-x-targetduration tag.  * Its value must is equal to or greater than the Extinf duration of any * Media segment that appears or would appear in     The Playlist file, * Typical Targer duration is seconds.    */* @see https://github.com/ossrs/srs/issues/304#issuecomment-74000081 */int targer_duration = 0;        for (it = Segments.begin (); It! = Segments.end (); ++it) {srshlssegment* segment = *it;    Target_duration = Srs_max (target_duration, (int) ceil (segment->duration));        } target_duration = Srs_max (target_duration, MAX_TD);        SS << "#EXT-x-targetduration:" << target_duration << srs_consts_lf;                 /* Write all segments */for (it = Segments.begin (); It! = Segments.end (); ++it) {srshlssegment* segment = *it;  if (Segment->is_sequence_header) {          /* #EXT-x-discontinuity\n */SS << "#EXT-x-discontinuity" << srs_consts_lf;        Srs_verbose ("Write m3u8 segment discontinuity success.");        }/* "#EXTINF: 4294967295.208,\n" */ss.precision (3);        SS.SETF (std::ios::fixed, Std::ios::floatfield);                SS << "#EXTINF:" << segment->duration << "No desc" << Srs_consts_lf;    /* {File name}\n */SS << Segment->uri << Srs_consts_lf; }/* Write m3u8 to writer.    */std::string m3u8 = Ss.str (); if (ret = Writer.write (char*) M3u8.c_str (), (int) m3u8.length (), NULL)) = = ERROR_SUCCESS) {srs_error ("writ E m3u8 failed.        ret=%d ", ret);    return ret;        } srs_info ("Write m3u8%s success.", M3u8_file.c_str ()); return ret;}
    • The function builds a m3u8 Playlist based on segments and writes the built data to the m3u8 file. The relevant knowledge of m3u8 can be referred to HLS protocol resolution.

    • Back in the Srshlscache::reap_segment function, when the call Srshlsmuxer::segment_close successfully returns, then call the Srshlsmuxer::segment_open function to open a new slice, the TS file.

4. Srshlsmuxer::segment_open
/* Open a new segment (a new TS file), * @param Segment_start_dts, use-To-calc the segment duration, * Use 0 for the F Irst segment of HLS.        */int Srshlsmuxer::segment_open (int64_t segment_start_dts) {int ret = ERROR_SUCCESS; /* Current:current writing segment.        The initialization is NULL */if (current) {Srs_warn ("ignore the segment open, for segment is already open.");    return ret; }/* When segment open, the current segment must is NULL.        */Srs_assert (!current); /* Load the default acodec from CONFIG.    */Srscodecaudio Default_acodec = SRSCODECAUDIOAAC; if (true) {/* HLS is not configured Hls_acodec, default returns "AAC" */std::string DEFAULT_ACODEC_STR = _srs_config->get_hls_ac        Odec (Req->vhost);            if (default_acodec_str = = "mp3") {default_acodec = SrsCodecAudioMP3;        Srs_info ("hls:use default MP3 Acodec");            } else if (Default_acodec_str = = "AAC") {Default_acodec = SRSCODECAUDIOAAC; Srs_info ("Hls:use default AAC Acodec ");            } else if (Default_acodec_str = = "an") {Default_acodec = srscodecaudiodisabled;        Srs_info ("hls:use default an Acodec for pure video");        } else {Srs_warn ("Hls:use AAC for other codec=%s", Default_acodec_str.c_str ()); }}/* Load the default vcodec from CONFIG.    */Srscodecvideo Default_vcodec = SRSCODECVIDEOAVC; if (true) {/* Hls_vcodec is not configured in HLS, the default is "H264" */std::string DEFAULT_VCODEC_STR = _srs_config->get_hls_        Vcodec (Req->vhost);            if (Default_vcodec_str = = "H264") {default_vcodec = SRSCODECVIDEOAVC;        Srs_info ("hls:use default H264 Vcodec");            } else if (default_vcodec_str = = "vn") {default_vcodec = srscodecvideodisabled;        Srs_info ("hls:use default vn vcodec for pure audio");        } else {Srs_warn ("Hls:use H264 for other codec=%s", Default_vcodec_str.c_str ()); }}/* New SEGMEnt. */current = new Srshlssegment (context, Should_write_cache, Should_write_file, Default_    Acodec, Default_vcodec); /* _sequence_no:sequence number in m3u8.    */current->sequence_no = _sequence_no++; /* If it is HLS first segment, then Segment_start_dts is 0, * otherwise DTS/Current->segment_start_dts = Segment_ for the currently received audio/video        Start_dts; /* Generate filename.    */* Ts_file: "[app]/[stream]-[seq].ts" */std::string ts_file = hls_ts_file; /* Ts_file: "live/livestream-[seq].ts" */Ts_file = Srs_path_build_stream (Ts_file, Req->vhost, Req->app, req->    Stream); /* Srshlsmuxer when constructed, initialize the value to False */if (Hls_ts_floor) {...} else {ts_file = srs_path_build_t    Imestamp (Ts_file);        } if (true) {Std::stringstream ss;        SS << current->sequence_no;    /* Ts_file:live/livestream-x.ts */ts_file = Srs_string_replace (Ts_file, "[seq]", ss.str ()); }/* Full_path:./obJs/nginx/html/live/livestream-x.ts */Current->full_path = Hls_path + "/" + ts_file; /* The TS URL, relative or absolute URL.    */std::string Ts_url = current->full_path; /* Ts_url:./objs/nginx/html/live/livestream-x.ts, * m3u8_dir:./objs/nginx/html/live */if (srs_string_starts_with (Ts_url, M3u8_dir))    {/* Ts_url:/livestream-x.ts */Ts_url = Ts_url.substr (M3u8_dir.length ());    } while (Srs_string_starts_with (Ts_url, "/")) {/* Ts_url:livestream-x.ts */Ts_url = TS_URL.SUBSTR (1);    }/* Current->uri: "" */Current->uri + = Hls_entry_prefix; if (!hls_entry_prefix.empty () &&!srs_string_ends_with (Hls_entry_prefix, "/")) {Current->uri + = "/"                ; /* Add the HTTP dir to URI.        */String Http_dir = Srs_path_dirname (M3u8_url);        if (!http_dir.empty ()) {Current->uri + = Http_dir + "/"; }}/* Current->uri:livestream-x.ts */Current->uri + = Ts_url; /* Create dir recursively for HLS.    */* Ts_dir:./objs/nginx/html/live */std::string Ts_dir = Srs_path_dirname (Current->full_path); if (should_write_file && (ret = srs_create_dir_recursively (ts_dir))! = ERROR_SUCCESS) {srs_error (" Create App dir%s failed.        ret=%d ", Ts_dir.c_str (), ret);    return ret; }/* Open temp TS file.     */* Tmp_file:./objs/nginx/html/live/livestream-x.ts.tmp */std::string tmp_file = Current->full_path + ". tmp"; if (ret = Current->muxer->open (Tmp_file.c_str ()))! = ERROR_SUCCESS) {srs_error ("Open HLS muxer failed.        ret=%d ", ret);    return ret; }/* Set the segment Muxer audio codec.    */if (acodec! = SrsCodecAudioReserved1) {current->muxer->update_acodec (ACODEC); } return ret;}
    • The function re-creates a Srshlssegment class object and opens a TS file. Go back to the Srshlscache::reap_segment function, and then call the Srshlsmuxer::flush_video and Srshlsmuxer::flush_audio functions to encapsulate all the audio and video cached in the cache as TS, and write to the open TS file. Here the two functions of the specific analysis process can refer to the SRS Srshls::on_audio and SRS Srshls::on_video detailed

SRS Srshlscache::reap_segment Detailed

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.