mirror of
https://github.com/ossrs/srs.git
synced 2025-02-13 11:51:57 +00:00
rewrite the ts remux of hls. 2.0.117
This commit is contained in:
parent
1ed3e283ab
commit
3c813847bd
5 changed files with 817 additions and 316 deletions
|
@ -313,7 +313,7 @@ int SrsHlsMuxer::update_acodec(SrsCodecAudio ac)
|
|||
return current->muxer->update_acodec(ac);
|
||||
}
|
||||
|
||||
int SrsHlsMuxer::flush_audio(SrsMpegtsFrame* af, SrsSimpleBuffer* ab)
|
||||
int SrsHlsMuxer::flush_audio(SrsTsCache* cache)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
|
@ -323,24 +323,24 @@ int SrsHlsMuxer::flush_audio(SrsMpegtsFrame* af, SrsSimpleBuffer* ab)
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (ab->length() <= 0) {
|
||||
if (!cache->audio || cache->audio->payload->length() <= 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// update the duration of segment.
|
||||
current->update_duration(af->pts);
|
||||
current->update_duration(cache->audio->pts);
|
||||
|
||||
if ((ret = current->muxer->write_audio(af, ab)) != ERROR_SUCCESS) {
|
||||
if ((ret = current->muxer->write_audio(cache->audio)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// write success, clear and free the buffer
|
||||
ab->erase(ab->length());
|
||||
// write success, clear and free the msg
|
||||
srs_freep(cache->audio);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsHlsMuxer::flush_video(SrsMpegtsFrame* /*af*/, SrsSimpleBuffer* /*ab*/, SrsMpegtsFrame* vf, SrsSimpleBuffer* vb)
|
||||
int SrsHlsMuxer::flush_video(SrsTsCache* cache)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
|
@ -350,17 +350,21 @@ int SrsHlsMuxer::flush_video(SrsMpegtsFrame* /*af*/, SrsSimpleBuffer* /*ab*/, Sr
|
|||
return ret;
|
||||
}
|
||||
|
||||
srs_assert(current);
|
||||
|
||||
// update the duration of segment.
|
||||
current->update_duration(vf->dts);
|
||||
|
||||
if ((ret = current->muxer->write_video(vf, vb)) != ERROR_SUCCESS) {
|
||||
if (!cache->video || cache->video->payload->length() <= 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// write success, clear and free the buffer
|
||||
vb->erase(vb->length());
|
||||
srs_assert(current);
|
||||
|
||||
// update the duration of segment.
|
||||
current->update_duration(cache->video->dts);
|
||||
|
||||
if ((ret = current->muxer->write_video(cache->video)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// write success, clear and free the msg
|
||||
srs_freep(cache->video);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -649,7 +653,7 @@ int SrsHlsCache::on_unpublish(SrsHlsMuxer* muxer)
|
|||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
if ((ret = muxer->flush_audio(cache->af, cache->ab)) != ERROR_SUCCESS) {
|
||||
if ((ret = muxer->flush_audio(cache)) != ERROR_SUCCESS) {
|
||||
srs_error("m3u8 muxer flush audio failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
@ -682,8 +686,8 @@ int SrsHlsCache::write_audio(SrsAvcAacCodec* codec, SrsHlsMuxer* muxer, int64_t
|
|||
}
|
||||
|
||||
// flush if buffer exceed max size.
|
||||
if (cache->ab->length() > SRS_AUTO_HLS_AUDIO_CACHE_SIZE) {
|
||||
if ((ret = muxer->flush_audio(cache->af, cache->ab)) != ERROR_SUCCESS) {
|
||||
if (cache->audio->payload->length() > SRS_AUTO_HLS_AUDIO_CACHE_SIZE) {
|
||||
if ((ret = muxer->flush_audio(cache)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
@ -692,8 +696,8 @@ int SrsHlsCache::write_audio(SrsAvcAacCodec* codec, SrsHlsMuxer* muxer, int64_t
|
|||
// in ms, audio delay to flush the audios.
|
||||
int64_t audio_delay = SRS_CONF_DEFAULT_AAC_DELAY;
|
||||
// flush if audio delay exceed
|
||||
if (pts - cache->audio_buffer_start_pts > audio_delay * 90) {
|
||||
if ((ret = muxer->flush_audio(cache->af, cache->ab)) != ERROR_SUCCESS) {
|
||||
if (pts - cache->audio->start_pts > audio_delay * 90) {
|
||||
if ((ret = muxer->flush_audio(cache)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
@ -707,7 +711,7 @@ int SrsHlsCache::write_audio(SrsAvcAacCodec* codec, SrsHlsMuxer* muxer, int64_t
|
|||
// we use absolutely overflow of segment to make jwplayer/ffplay happy
|
||||
// @see https://github.com/winlinvip/simple-rtmp-server/issues/151#issuecomment-71155184
|
||||
if (muxer->is_segment_absolutely_overflow()) {
|
||||
if ((ret = reap_segment("audio", muxer, cache->af->pts)) != ERROR_SUCCESS) {
|
||||
if ((ret = reap_segment("audio", muxer, cache->audio->pts)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
@ -728,14 +732,14 @@ int SrsHlsCache::write_video(SrsAvcAacCodec* codec, SrsHlsMuxer* muxer, int64_t
|
|||
// 1. base on gop.
|
||||
// 2. some gops duration overflow.
|
||||
if (sample->frame_type == SrsCodecVideoAVCFrameKeyFrame && muxer->is_segment_overflow()) {
|
||||
if ((ret = reap_segment("video", muxer, cache->vf->dts)) != ERROR_SUCCESS) {
|
||||
if ((ret = reap_segment("video", muxer, cache->video->dts)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// flush video when got one
|
||||
if ((ret = muxer->flush_video(cache->af, cache->ab, cache->vf, cache->vb)) != ERROR_SUCCESS) {
|
||||
if ((ret = muxer->flush_video(cache)) != ERROR_SUCCESS) {
|
||||
srs_error("m3u8 muxer flush video failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
@ -761,7 +765,7 @@ int SrsHlsCache::reap_segment(string log_desc, SrsHlsMuxer* muxer, int64_t segme
|
|||
// TODO: fresh segment begin with audio or video?
|
||||
|
||||
// segment open, flush video first.
|
||||
if ((ret = muxer->flush_video(cache->af, cache->ab, cache->vf, cache->vb)) != ERROR_SUCCESS) {
|
||||
if ((ret = muxer->flush_video(cache)) != ERROR_SUCCESS) {
|
||||
srs_error("m3u8 muxer flush video failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
@ -769,7 +773,7 @@ int SrsHlsCache::reap_segment(string log_desc, SrsHlsMuxer* muxer, int64_t segme
|
|||
// segment open, flush the audio.
|
||||
// @see: ngx_rtmp_hls_open_fragment
|
||||
/* start fragment with audio to make iPhone happy */
|
||||
if ((ret = muxer->flush_audio(cache->af, cache->ab)) != ERROR_SUCCESS) {
|
||||
if ((ret = muxer->flush_audio(cache)) != ERROR_SUCCESS) {
|
||||
srs_error("m3u8 muxer flush audio failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -42,7 +42,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
|
||||
class SrsSharedPtrMessage;
|
||||
class SrsCodecSample;
|
||||
class SrsMpegtsFrame;
|
||||
class SrsAmf0Object;
|
||||
class SrsRtmpJitter;
|
||||
class SrsTSMuxer;
|
||||
|
@ -55,6 +54,7 @@ class SrsSimpleBuffer;
|
|||
class SrsTsAacJitter;
|
||||
class SrsTsCache;
|
||||
class SrsHlsSegment;
|
||||
class SrsTsCache;
|
||||
|
||||
/**
|
||||
* the handler for hls event.
|
||||
|
@ -224,8 +224,8 @@ public:
|
|||
virtual bool is_segment_absolutely_overflow();
|
||||
public:
|
||||
virtual int update_acodec(SrsCodecAudio ac);
|
||||
virtual int flush_audio(SrsMpegtsFrame* af, SrsSimpleBuffer* ab);
|
||||
virtual int flush_video(SrsMpegtsFrame* af, SrsSimpleBuffer* ab, SrsMpegtsFrame* vf, SrsSimpleBuffer* vb);
|
||||
virtual int flush_audio(SrsTsCache* cache);
|
||||
virtual int flush_video(SrsTsCache* cache);
|
||||
/**
|
||||
* close segment(ts).
|
||||
* @param log_desc the description for log.
|
||||
|
|
|
@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
// current release version
|
||||
#define VERSION_MAJOR 2
|
||||
#define VERSION_MINOR 0
|
||||
#define VERSION_REVISION 116
|
||||
#define VERSION_REVISION 117
|
||||
|
||||
// server info.
|
||||
#define RTMP_SIG_SRS_KEY "SRS"
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -185,6 +185,8 @@ struct SrsTsChannel
|
|||
SrsTsPidApply apply;
|
||||
SrsTsStream stream;
|
||||
SrsTsMessage* msg;
|
||||
// for encoder.
|
||||
u_int8_t continuity_counter;
|
||||
|
||||
SrsTsChannel();
|
||||
virtual ~SrsTsChannel();
|
||||
|
@ -209,13 +211,17 @@ enum SrsTsPESStreamId
|
|||
// ISO/IEC 13818-3 or ISO/IEC 11172-3 or ISO/IEC 13818-7 or ISO/IEC
|
||||
// 14496-3 audio stream number x xxxx
|
||||
// ((sid >> 5) & 0x07) == SrsTsPESStreamIdAudio
|
||||
SrsTsPESStreamIdAudio = 0x06, // 0b110
|
||||
// @remark, use SrsTsPESStreamIdAudioCommon as actually audio, SrsTsPESStreamIdAudio to check whether audio.
|
||||
SrsTsPESStreamIdAudioChecker = 0x06, // 0b110
|
||||
SrsTsPESStreamIdAudioCommon = 0xc0,
|
||||
|
||||
// 1110 xxxx
|
||||
// ITU-T Rec. H.262 | ISO/IEC 13818-2 or ISO/IEC 11172-2 or ISO/IEC
|
||||
// 14496-2 video stream number xxxx
|
||||
// ((stream_id >> 4) & 0x0f) == SrsTsPESStreamIdVideo
|
||||
SrsTsPESStreamIdVideo = 0x0e, // 0b1110
|
||||
// @remark, use SrsTsPESStreamIdVideoCommon as actually video, SrsTsPESStreamIdVideo to check whether video.
|
||||
SrsTsPESStreamIdVideoChecker = 0x0e, // 0b1110
|
||||
SrsTsPESStreamIdVideoCommon = 0xe0,
|
||||
|
||||
// ECM_stream
|
||||
SrsTsPESStreamIdEcmStream = 0xf0, // 0b11110000
|
||||
|
@ -253,8 +259,20 @@ enum SrsTsPESStreamId
|
|||
class SrsTsMessage
|
||||
{
|
||||
public:
|
||||
// decoder only,
|
||||
// the ts messgae does not use them,
|
||||
// for user to get the channel and packet.
|
||||
SrsTsChannel* channel;
|
||||
SrsTsPacket* packet;
|
||||
public:
|
||||
// the audio cache buffer start pts, to flush audio if full.
|
||||
// @remark the pts is not the adjust one, it's the orignal pts.
|
||||
int64_t start_pts;
|
||||
// whether this message with pcr info,
|
||||
// generally, the video IDR(I frame, the keyframe of h.264) carray the pcr info.
|
||||
bool write_pcr;
|
||||
// whether got discontinuity ts, for example, sequence header changed.
|
||||
bool discontinuity;
|
||||
public:
|
||||
// the timestamp in 90khz
|
||||
int64_t dts;
|
||||
|
@ -269,8 +287,9 @@ public:
|
|||
// the payload bytes.
|
||||
SrsSimpleBuffer* payload;
|
||||
public:
|
||||
SrsTsMessage(SrsTsChannel* c, SrsTsPacket* p);
|
||||
SrsTsMessage(SrsTsChannel* c = NULL, SrsTsPacket* p = NULL);
|
||||
virtual ~SrsTsMessage();
|
||||
// decoder
|
||||
public:
|
||||
/**
|
||||
* dumps all bytes in stream to ts message.
|
||||
|
@ -361,15 +380,14 @@ public:
|
|||
public:
|
||||
/**
|
||||
* write the PES packet, the video/audio stream.
|
||||
* @param frame the video/audio frame info.
|
||||
* @param payload the video/audio payload bytes.
|
||||
* @param msg the video/audio msg to write to ts.
|
||||
* @param vc the video codec, write the PAT/PMT table when changed.
|
||||
* @param ac the audio codec, write the PAT/PMT table when changed.
|
||||
*/
|
||||
virtual int encode(SrsFileWriter* writer, SrsMpegtsFrame* frame, SrsSimpleBuffer* payload, SrsCodecVideo vc, SrsCodecAudio ac);
|
||||
virtual int encode(SrsFileWriter* writer, SrsTsMessage* msg, SrsCodecVideo vc, SrsCodecAudio ac);
|
||||
private:
|
||||
virtual int encode_pat_pmt(SrsFileWriter* writer, SrsCodecVideo vcodec, SrsCodecAudio acodec);
|
||||
virtual int encode_pes(SrsFileWriter* writer, SrsMpegtsFrame* frame, SrsSimpleBuffer* payload);
|
||||
virtual int encode_pat_pmt(SrsFileWriter* writer, int16_t vpid, SrsTsStream vs, int16_t apid, SrsTsStream as);
|
||||
virtual int encode_pes(SrsFileWriter* writer, SrsTsMessage* msg, int16_t pid, SrsTsStream sid);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -478,9 +496,22 @@ public:
|
|||
public:
|
||||
virtual int size();
|
||||
virtual int encode(SrsStream* stream);
|
||||
virtual void padding(int nb_stuffings);
|
||||
public:
|
||||
static SrsTsPacket* create_pat(SrsTsContext* context, int16_t pmt_number, int16_t pmt_pid);
|
||||
static SrsTsPacket* create_pmt(SrsTsContext* context, int16_t pmt_number, int16_t pmt_pid, int16_t vpid, SrsTsStream vs, int16_t apid, SrsTsStream as);
|
||||
static SrsTsPacket* create_pat(SrsTsContext* context,
|
||||
int16_t pmt_number, int16_t pmt_pid
|
||||
);
|
||||
static SrsTsPacket* create_pmt(SrsTsContext* context,
|
||||
int16_t pmt_number, int16_t pmt_pid, int16_t vpid, SrsTsStream vs,
|
||||
int16_t apid, SrsTsStream as
|
||||
);
|
||||
static SrsTsPacket* create_pes_first(SrsTsContext* context,
|
||||
int16_t pid, SrsTsPESStreamId sid, u_int8_t continuity_counter, bool discontinuity,
|
||||
int64_t pcr, int64_t dts, int64_t pts, int size
|
||||
);
|
||||
static SrsTsPacket* create_pes_continue(SrsTsContext* context,
|
||||
int16_t pid, SrsTsPESStreamId sid, u_int8_t continuity_counter
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -627,7 +658,10 @@ public:
|
|||
* the last bit of the program_clock_reference_base at the input of the system target decoder.
|
||||
*/
|
||||
int64_t program_clock_reference_base; //33bits
|
||||
//6bits reserved.
|
||||
/**
|
||||
* 6bits reserved, must be '1'
|
||||
*/
|
||||
int8_t const1_value0; // 6bits
|
||||
int16_t program_clock_reference_extension; //9bits
|
||||
|
||||
// if OPCR_flag, 6B
|
||||
|
@ -646,7 +680,10 @@ public:
|
|||
* in the original single program Transport Stream.
|
||||
*/
|
||||
int64_t original_program_clock_reference_base; //33bits
|
||||
//6bits reserved.
|
||||
/**
|
||||
* 6bits reserved, must be '1'
|
||||
*/
|
||||
int8_t const1_value2; // 6bits
|
||||
int16_t original_program_clock_reference_extension; //9bits
|
||||
|
||||
// if splicing_point_flag, 1B
|
||||
|
@ -711,7 +748,10 @@ public:
|
|||
* constraints indicated by the splice_type value.
|
||||
*/
|
||||
int8_t seamless_splice_flag; //1bit
|
||||
//5bits reserved
|
||||
/**
|
||||
* reserved 5bits, must be '1'
|
||||
*/
|
||||
int8_t const1_value1; //5bits
|
||||
// if ltw_flag, 2B
|
||||
/**
|
||||
* (legal time window_valid_flag) - This is a 1-bit field which when set to '1' indicates that the value of the
|
||||
|
@ -856,6 +896,7 @@ public:
|
|||
* elementary stream type as defined in Table 2-18. In Transport Streams, the elementary stream type is specified in the
|
||||
* Program Specific Information as specified in 2.4.4.
|
||||
*/
|
||||
// @see SrsTsPESStreamId, value can be SrsTsPESStreamIdAudioCommon or SrsTsPESStreamIdVideoCommon.
|
||||
u_int8_t stream_id; //8bits
|
||||
// 2B
|
||||
/**
|
||||
|
@ -866,7 +907,10 @@ public:
|
|||
u_int16_t PES_packet_length; //16bits
|
||||
|
||||
// 1B
|
||||
// 2bits const '10'
|
||||
/**
|
||||
* 2bits const '10'
|
||||
*/
|
||||
int8_t const2bits; //2bits
|
||||
/**
|
||||
* The 2-bit PES_scrambling_control field indicates the scrambling mode of the PES packet
|
||||
* payload. When scrambling is performed at the PES level, the PES packet header, including the optional fields when
|
||||
|
@ -1068,7 +1112,10 @@ public:
|
|||
* PES header.
|
||||
*/
|
||||
int8_t P_STD_buffer_flag; //1bit
|
||||
// reserved 3bits
|
||||
/**
|
||||
* reverved value, must be '1'
|
||||
*/
|
||||
int8_t const1_value0; //3bits
|
||||
/**
|
||||
* A 1-bit field which when set to '1' indicates the presence of the PES_extension_field_length
|
||||
* field and associated fields. When set to a value of '0' this indicates that the PES_extension_field_length field and any
|
||||
|
@ -1179,6 +1226,7 @@ public:
|
|||
virtual int encode(SrsStream* stream);
|
||||
private:
|
||||
virtual int decode_33bits_dts_pts(SrsStream* stream, int64_t* pv);
|
||||
virtual int encode_33bits_dts_pts(SrsStream* stream, u_int8_t fb, int64_t v);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1516,52 +1564,18 @@ public:
|
|||
virtual int update_acodec(SrsCodecAudio ac);
|
||||
/**
|
||||
* write an audio frame to ts,
|
||||
* @remark write PSI first when not write yet.
|
||||
*/
|
||||
virtual int write_audio(SrsMpegtsFrame* af, SrsSimpleBuffer* ab);
|
||||
virtual int write_audio(SrsTsMessage* audio);
|
||||
/**
|
||||
* write a video frame to ts,
|
||||
* @remark write PSI first when not write yet.
|
||||
*/
|
||||
virtual int write_video(SrsMpegtsFrame* vf, SrsSimpleBuffer* vb);
|
||||
virtual int write_video(SrsTsMessage* video);
|
||||
/**
|
||||
* close the writer.
|
||||
*/
|
||||
virtual void close();
|
||||
};
|
||||
|
||||
/**
|
||||
* jitter correct for audio,
|
||||
* the sample rate 44100/32000 will lost precise,
|
||||
* when mp4/ts(tbn=90000) covert to flv/rtmp(1000),
|
||||
* so the Hls on ipad or iphone will corrupt,
|
||||
* @see nginx-rtmp: est_pts
|
||||
*/
|
||||
class SrsTsAacJitter
|
||||
{
|
||||
private:
|
||||
int64_t base_pts;
|
||||
int64_t nb_samples;
|
||||
int sync_ms;
|
||||
public:
|
||||
SrsTsAacJitter();
|
||||
virtual ~SrsTsAacJitter();
|
||||
/**
|
||||
* when buffer start, calc the "correct" pts for ts,
|
||||
* @param flv_pts, the flv pts calc from flv header timestamp,
|
||||
* @param sample_rate, the sample rate in format(flv/RTMP packet header).
|
||||
* @param aac_sample_rate, the sample rate in codec(sequence header).
|
||||
* @return the calc correct pts.
|
||||
*/
|
||||
virtual int64_t on_buffer_start(int64_t flv_pts, int sample_rate, int aac_sample_rate);
|
||||
/**
|
||||
* when buffer continue, muxer donot write to file,
|
||||
* the audio buffer continue grow and donot need a pts,
|
||||
* for the ts audio PES packet only has one pts at the first time.
|
||||
*/
|
||||
virtual void on_buffer_continue();
|
||||
};
|
||||
|
||||
/**
|
||||
* ts stream cache,
|
||||
* use to cache ts stream.
|
||||
|
@ -1575,18 +1589,9 @@ public:
|
|||
class SrsTsCache
|
||||
{
|
||||
public:
|
||||
// current frame and buffer
|
||||
SrsMpegtsFrame* af;
|
||||
SrsSimpleBuffer* ab;
|
||||
SrsMpegtsFrame* vf;
|
||||
SrsSimpleBuffer* vb;
|
||||
public:
|
||||
// the audio cache buffer start pts, to flush audio if full.
|
||||
// @remark the pts is not the adjust one, it's the orignal pts.
|
||||
int64_t audio_buffer_start_pts;
|
||||
protected:
|
||||
// time jitter for aac
|
||||
SrsTsAacJitter* aac_jitter;
|
||||
// current ts message.
|
||||
SrsTsMessage* audio;
|
||||
SrsTsMessage* video;
|
||||
public:
|
||||
SrsTsCache();
|
||||
virtual ~SrsTsCache();
|
||||
|
@ -1594,14 +1599,15 @@ public:
|
|||
/**
|
||||
* write audio to cache
|
||||
*/
|
||||
virtual int cache_audio(SrsAvcAacCodec* codec, int64_t pts, SrsCodecSample* sample);
|
||||
virtual int cache_audio(SrsAvcAacCodec* codec, int64_t dts, SrsCodecSample* sample);
|
||||
/**
|
||||
* write video to muxer.
|
||||
*/
|
||||
virtual int cache_video(SrsAvcAacCodec* codec, int64_t dts, SrsCodecSample* sample);
|
||||
private:
|
||||
virtual int do_cache_audio(SrsAvcAacCodec* codec, SrsCodecSample* sample);
|
||||
virtual int do_cache_video(SrsAvcAacCodec* codec, SrsCodecSample* sample);
|
||||
virtual int do_cache_mp3(SrsAvcAacCodec* codec, SrsCodecSample* sample);
|
||||
virtual int do_cache_aac(SrsAvcAacCodec* codec, SrsCodecSample* sample);
|
||||
virtual int do_cache_avc(SrsAvcAacCodec* codec, SrsCodecSample* sample);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue