mirror of
https://github.com/ossrs/srs.git
synced 2025-02-13 03:41:55 +00:00
refine hls codec sample info. 0.9.161
This commit is contained in:
parent
f020690ed7
commit
a4d3283cdd
5 changed files with 105 additions and 83 deletions
|
@ -30,26 +30,14 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
#include <srs_kernel_codec.hpp>
|
||||
#include <srs_kernel_stream.hpp>
|
||||
|
||||
SrsCodecBuffer::SrsCodecBuffer()
|
||||
SrsCodecSampleUnit::SrsCodecSampleUnit()
|
||||
{
|
||||
size = 0;
|
||||
bytes = NULL;
|
||||
}
|
||||
|
||||
void SrsCodecBuffer::append(void* data, int len)
|
||||
SrsCodecSampleUnit::~SrsCodecSampleUnit()
|
||||
{
|
||||
srs_assert(data);
|
||||
srs_assert(len > 0);
|
||||
|
||||
bytes = (char*)realloc(bytes, size + len);
|
||||
memcpy(bytes + size, data, len);
|
||||
size += len;
|
||||
}
|
||||
|
||||
void SrsCodecBuffer::free()
|
||||
{
|
||||
size = 0;
|
||||
srs_freep(bytes);
|
||||
}
|
||||
|
||||
SrsCodecSample::SrsCodecSample()
|
||||
|
@ -64,7 +52,7 @@ SrsCodecSample::~SrsCodecSample()
|
|||
void SrsCodecSample::clear()
|
||||
{
|
||||
is_video = false;
|
||||
nb_buffers = 0;
|
||||
nb_sample_units = 0;
|
||||
|
||||
cts = 0;
|
||||
frame_type = SrsCodecVideoAVCFrameReserved;
|
||||
|
@ -76,20 +64,20 @@ void SrsCodecSample::clear()
|
|||
aac_packet_type = SrsCodecAudioTypeReserved;
|
||||
}
|
||||
|
||||
int SrsCodecSample::add_sample(char* bytes, int size)
|
||||
int SrsCodecSample::add_sample_unit(char* bytes, int size)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
if (nb_buffers >= SRS_MAX_CODEC_SAMPLE) {
|
||||
if (nb_sample_units >= SRS_MAX_CODEC_SAMPLE) {
|
||||
ret = ERROR_HLS_DECODE_ERROR;
|
||||
srs_error("hls decode samples error, "
|
||||
"exceed the max count: %d, ret=%d", SRS_MAX_CODEC_SAMPLE, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
SrsCodecBuffer* buf = &buffers[nb_buffers++];
|
||||
buf->bytes = bytes;
|
||||
buf->size = size;
|
||||
SrsCodecSampleUnit* sample_unit = &sample_units[nb_sample_units++];
|
||||
sample_unit->bytes = bytes;
|
||||
sample_unit->size = size;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -239,7 +227,7 @@ int SrsAvcAacCodec::audio_aac_demux(char* data, int size, SrsCodecSample* sample
|
|||
|
||||
// Raw AAC frame data in UI8 []
|
||||
// 6.3 Raw Data, aac-iso-13818-7.pdf, page 28
|
||||
if ((ret = sample->add_sample(stream->data() + stream->pos(), stream->size() - stream->pos())) != ERROR_SUCCESS) {
|
||||
if ((ret = sample->add_sample_unit(stream->data() + stream->pos(), stream->size() - stream->pos())) != ERROR_SUCCESS) {
|
||||
srs_error("hls add audio sample failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
@ -445,7 +433,7 @@ int SrsAvcAacCodec::video_avc_demux(char* data, int size, SrsCodecSample* sample
|
|||
return ret;
|
||||
}
|
||||
// 7.3.1 NAL unit syntax, H.264-AVC-ISO_IEC_14496-10.pdf, page 44.
|
||||
if ((ret = sample->add_sample(stream->data() + stream->pos(), NALUnitLength)) != ERROR_SUCCESS) {
|
||||
if ((ret = sample->add_sample_unit(stream->data() + stream->pos(), NALUnitLength)) != ERROR_SUCCESS) {
|
||||
srs_error("hls add video sample failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -89,30 +89,38 @@ enum SrsCodecAudioSoundType
|
|||
};
|
||||
|
||||
/**
|
||||
* buffer indicates the position and size.
|
||||
* the codec sample unit.
|
||||
* for h.264 video packet, a NALU is a sample unit.
|
||||
* for aac raw audio packet, a NALU is the entire aac raw data.
|
||||
* for sequence header, it's not a sample unit.
|
||||
*/
|
||||
class SrsCodecBuffer
|
||||
class SrsCodecSampleUnit
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @remark user must manage the bytes.
|
||||
* the sample bytes is directly ptr to packet bytes,
|
||||
* user should never use it when packet destroyed.
|
||||
*/
|
||||
int size;
|
||||
char* bytes;
|
||||
public:
|
||||
SrsCodecBuffer();
|
||||
void append(void* data, int len);
|
||||
public:
|
||||
/**
|
||||
* free the bytes,
|
||||
* user can invoke it to free the bytes,
|
||||
* the SrsCodecBuffer never free automatically.
|
||||
*/
|
||||
void free();
|
||||
SrsCodecSampleUnit();
|
||||
virtual ~SrsCodecSampleUnit();
|
||||
};
|
||||
|
||||
/**
|
||||
* the samples in the flv audio/video packet.
|
||||
* the sample used to analysis a video/audio packet,
|
||||
* split the h.264 NALUs to buffers, or aac raw data to a buffer,
|
||||
* and decode the video/audio specified infos.
|
||||
*
|
||||
* the sample unit:
|
||||
* a video packet codec in h.264 contains many NALUs, each is a sample unit.
|
||||
* a audio packet codec in aac is a sample unit.
|
||||
* @remark, the video/audio sequence header is not sample unit,
|
||||
* all sequence header stores as extra data,
|
||||
* @see SrsAvcAacCodec.avc_extra_data and SrsAvcAacCodec.aac_extra_data
|
||||
* @remark, user must clear all samples before decode a new video/audio packet.
|
||||
*/
|
||||
class SrsCodecSample
|
||||
{
|
||||
|
@ -123,12 +131,14 @@ public:
|
|||
* generally, aac audio packet corresponding to one buffer,
|
||||
* where avc/h264 video packet may contains multiple buffer.
|
||||
*/
|
||||
int nb_buffers;
|
||||
SrsCodecBuffer buffers[SRS_MAX_CODEC_SAMPLE];
|
||||
int nb_sample_units;
|
||||
SrsCodecSampleUnit sample_units[SRS_MAX_CODEC_SAMPLE];
|
||||
public:
|
||||
bool is_video;
|
||||
// CompositionTime, video_file_format_spec_v10_1.pdf, page 78.
|
||||
// cts = pts - dts, where dts = flvheader->timestamp.
|
||||
/**
|
||||
* CompositionTime, video_file_format_spec_v10_1.pdf, page 78.
|
||||
* cts = pts - dts, where dts = flvheader->timestamp.
|
||||
*/
|
||||
int32_t cts;
|
||||
public:
|
||||
// video specified
|
||||
|
@ -143,13 +153,37 @@ public:
|
|||
public:
|
||||
SrsCodecSample();
|
||||
virtual ~SrsCodecSample();
|
||||
public:
|
||||
/**
|
||||
* clear all samples.
|
||||
* the sample units never copy the bytes, it directly use the ptr,
|
||||
* so when video/audio packet is destroyed, the sample must be clear.
|
||||
* in a word, user must clear sample before demux it.
|
||||
* @remark demux sample use SrsAvcAacCodec.audio_aac_demux or video_avc_demux.
|
||||
*/
|
||||
void clear();
|
||||
int add_sample(char* bytes, int size);
|
||||
/**
|
||||
* add the a sample unit, it's a h.264 NALU or aac raw data.
|
||||
* the sample unit directly use the ptr of packet bytes,
|
||||
* so user must never use sample unit when packet is destroyed.
|
||||
* in a word, user must clear sample before demux it.
|
||||
*/
|
||||
int add_sample_unit(char* bytes, int size);
|
||||
};
|
||||
|
||||
/**
|
||||
* the h264/avc and aac codec, for media stream.
|
||||
* to decode the stream of avc/aac for hls.
|
||||
*
|
||||
* to demux the FLV/RTMP video/audio packet to sample,
|
||||
* add each NALUs of h.264 as a sample unit to sample,
|
||||
* while the entire aac raw data as a sample unit.
|
||||
*
|
||||
* for sequence header,
|
||||
* demux it and save it in the avc_extra_data and aac_extra_data,
|
||||
*
|
||||
* for the codec info, such as audio sample rate,
|
||||
* decode from FLV/RTMP header, then use codec info in sequence
|
||||
* header to override it.
|
||||
*/
|
||||
class SrsAvcAacCodec
|
||||
{
|
||||
|
|
|
@ -68,6 +68,7 @@ using namespace std;
|
|||
#include <srs_kernel_utility.hpp>
|
||||
#include <srs_app_avc_aac.hpp>
|
||||
#include <srs_kernel_file.hpp>
|
||||
#include <srs_kernel_buffer.hpp>
|
||||
|
||||
// max PES packets size to flush the video.
|
||||
#define SRS_AUTO_HLS_AUDIO_CACHE_SIZE 1024 * 1024
|
||||
|
@ -195,16 +196,16 @@ public:
|
|||
|
||||
return ret;
|
||||
}
|
||||
static int write_frame(SrsFileWriter* writer, SrsMpegtsFrame* frame, SrsCodecBuffer* buffer)
|
||||
static int write_frame(SrsFileWriter* writer, SrsMpegtsFrame* frame, SrsBuffer* buffer)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
if (!buffer->bytes || buffer->size <= 0) {
|
||||
if (!buffer->bytes() || buffer->length() <= 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
char* last = buffer->bytes + buffer->size;
|
||||
char* pos = buffer->bytes;
|
||||
char* last = buffer->bytes() + buffer->length();
|
||||
char* pos = buffer->bytes();
|
||||
|
||||
bool first = true;
|
||||
while (pos < last) {
|
||||
|
@ -478,7 +479,7 @@ int SrsTSMuxer::open(string _path)
|
|||
return ret;
|
||||
}
|
||||
|
||||
int SrsTSMuxer::write_audio(SrsMpegtsFrame* af, SrsCodecBuffer* ab)
|
||||
int SrsTSMuxer::write_audio(SrsMpegtsFrame* af, SrsBuffer* ab)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
|
@ -489,7 +490,7 @@ int SrsTSMuxer::write_audio(SrsMpegtsFrame* af, SrsCodecBuffer* ab)
|
|||
return ret;
|
||||
}
|
||||
|
||||
int SrsTSMuxer::write_video(SrsMpegtsFrame* vf, SrsCodecBuffer* vb)
|
||||
int SrsTSMuxer::write_video(SrsMpegtsFrame* vf, SrsBuffer* vb)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
|
@ -651,7 +652,7 @@ bool SrsHlsMuxer::is_segment_overflow()
|
|||
return current->duration >= hls_fragment;
|
||||
}
|
||||
|
||||
int SrsHlsMuxer::flush_audio(SrsMpegtsFrame* af, SrsCodecBuffer* ab)
|
||||
int SrsHlsMuxer::flush_audio(SrsMpegtsFrame* af, SrsBuffer* ab)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
|
@ -661,7 +662,7 @@ int SrsHlsMuxer::flush_audio(SrsMpegtsFrame* af, SrsCodecBuffer* ab)
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (ab->size <= 0) {
|
||||
if (ab->length() <= 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -673,13 +674,12 @@ int SrsHlsMuxer::flush_audio(SrsMpegtsFrame* af, SrsCodecBuffer* ab)
|
|||
}
|
||||
|
||||
// write success, clear and free the buffer
|
||||
ab->free();
|
||||
ab->erase(ab->length());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsHlsMuxer::flush_video(
|
||||
SrsMpegtsFrame* af, SrsCodecBuffer* ab, SrsMpegtsFrame* vf, SrsCodecBuffer* vb)
|
||||
int SrsHlsMuxer::flush_video(SrsMpegtsFrame* af, SrsBuffer* ab, SrsMpegtsFrame* vf, SrsBuffer* vb)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
|
@ -699,7 +699,7 @@ int SrsHlsMuxer::flush_video(
|
|||
}
|
||||
|
||||
// write success, clear and free the buffer
|
||||
vb->free();
|
||||
vb->erase(vb->length());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -962,8 +962,8 @@ SrsHlsCache::SrsHlsCache()
|
|||
{
|
||||
aac_jitter = new SrsHlsAacJitter();
|
||||
|
||||
ab = new SrsCodecBuffer();
|
||||
vb = new SrsCodecBuffer();
|
||||
ab = new SrsBuffer();
|
||||
vb = new SrsBuffer();
|
||||
|
||||
af = new SrsMpegtsFrame();
|
||||
vf = new SrsMpegtsFrame();
|
||||
|
@ -975,8 +975,8 @@ SrsHlsCache::~SrsHlsCache()
|
|||
{
|
||||
srs_freep(aac_jitter);
|
||||
|
||||
ab->free();
|
||||
vb->free();
|
||||
ab->erase(ab->length());
|
||||
vb->erase(vb->length());
|
||||
|
||||
srs_freep(ab);
|
||||
srs_freep(vb);
|
||||
|
@ -1051,7 +1051,7 @@ int SrsHlsCache::write_audio(SrsAvcAacCodec* codec, SrsHlsMuxer* muxer, int64_t
|
|||
int ret = ERROR_SUCCESS;
|
||||
|
||||
// start buffer, set the af
|
||||
if (ab->size == 0) {
|
||||
if (ab->length() == 0) {
|
||||
pts = aac_jitter->on_buffer_start(pts, sample->sound_rate, codec->aac_sample_rate);
|
||||
|
||||
af->dts = af->pts = audio_buffer_start_pts = pts;
|
||||
|
@ -1067,7 +1067,7 @@ int SrsHlsCache::write_audio(SrsAvcAacCodec* codec, SrsHlsMuxer* muxer, int64_t
|
|||
}
|
||||
|
||||
// flush if buffer exceed max size.
|
||||
if (ab->size > SRS_AUTO_HLS_AUDIO_CACHE_SIZE) {
|
||||
if (ab->length() > SRS_AUTO_HLS_AUDIO_CACHE_SIZE) {
|
||||
if ((ret = muxer->flush_audio(af, ab)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
@ -1159,11 +1159,11 @@ int SrsHlsCache::cache_audio(SrsAvcAacCodec* codec, SrsCodecSample* sample)
|
|||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
for (int i = 0; i < sample->nb_buffers; i++) {
|
||||
SrsCodecBuffer* buf = &sample->buffers[i];
|
||||
int32_t size = buf->size;
|
||||
for (int i = 0; i < sample->nb_sample_units; i++) {
|
||||
SrsCodecSampleUnit* sample_unit = &sample->sample_units[i];
|
||||
int32_t size = sample_unit->size;
|
||||
|
||||
if (!buf->bytes || size <= 0 || size > 0x1fff) {
|
||||
if (!sample_unit->bytes || size <= 0 || size > 0x1fff) {
|
||||
ret = ERROR_HLS_AAC_FRAME_LENGTH;
|
||||
srs_error("invalid aac frame length=%d, ret=%d", size, ret);
|
||||
return ret;
|
||||
|
@ -1215,8 +1215,8 @@ int SrsHlsCache::cache_audio(SrsAvcAacCodec* codec, SrsCodecSample* sample)
|
|||
adts_header[5] |= 0x1f;
|
||||
|
||||
// copy to audio buffer
|
||||
ab->append(adts_header, sizeof(adts_header));
|
||||
ab->append(buf->bytes, buf->size);
|
||||
ab->append((const char*)adts_header, sizeof(adts_header));
|
||||
ab->append(sample_unit->bytes, sample_unit->size);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -1239,11 +1239,11 @@ int SrsHlsCache::cache_video(SrsAvcAacCodec* codec, SrsCodecSample* sample)
|
|||
* xxxxxxx // data bytes.
|
||||
* so, for each sample, we append header in aud_nal, then appends the bytes in sample.
|
||||
*/
|
||||
for (int i = 0; i < sample->nb_buffers; i++) {
|
||||
SrsCodecBuffer* buf = &sample->buffers[i];
|
||||
int32_t size = buf->size;
|
||||
for (int i = 0; i < sample->nb_sample_units; i++) {
|
||||
SrsCodecSampleUnit* sample_unit = &sample->sample_units[i];
|
||||
int32_t size = sample_unit->size;
|
||||
|
||||
if (!buf->bytes || size <= 0) {
|
||||
if (!sample_unit->bytes || size <= 0) {
|
||||
ret = ERROR_HLS_AVC_SAMPLE_SIZE;
|
||||
srs_error("invalid avc sample length=%d, ret=%d", size, ret);
|
||||
return ret;
|
||||
|
@ -1259,7 +1259,7 @@ int SrsHlsCache::cache_video(SrsAvcAacCodec* codec, SrsCodecSample* sample)
|
|||
// 5bits, 7.3.1 NAL unit syntax,
|
||||
// H.264-AVC-ISO_IEC_14496-10.pdf, page 44.
|
||||
u_int8_t nal_unit_type;
|
||||
nal_unit_type = *buf->bytes;
|
||||
nal_unit_type = *sample_unit->bytes;
|
||||
nal_unit_type &= 0x1f;
|
||||
|
||||
// @see: ngx_rtmp_hls_video
|
||||
|
@ -1277,7 +1277,7 @@ int SrsHlsCache::cache_video(SrsAvcAacCodec* codec, SrsCodecSample* sample)
|
|||
}
|
||||
if (nal_unit_type == 1 || nal_unit_type == 5 || nal_unit_type == 6) {
|
||||
// for type 6, append a aud with type 9.
|
||||
vb->append(aud_nal, sizeof(aud_nal));
|
||||
vb->append((const char*)aud_nal, sizeof(aud_nal));
|
||||
aud_sent = true;
|
||||
}
|
||||
}
|
||||
|
@ -1290,13 +1290,13 @@ int SrsHlsCache::cache_video(SrsAvcAacCodec* codec, SrsCodecSample* sample)
|
|||
// @see: ngx_rtmp_hls_append_sps_pps
|
||||
if (codec->sequenceParameterSetLength > 0) {
|
||||
// AnnexB prefix, for sps always 4 bytes header
|
||||
vb->append(aud_nal, 4);
|
||||
vb->append((const char*)aud_nal, 4);
|
||||
// sps
|
||||
vb->append(codec->sequenceParameterSetNALUnit, codec->sequenceParameterSetLength);
|
||||
}
|
||||
if (codec->pictureParameterSetLength > 0) {
|
||||
// AnnexB prefix, for pps always 4 bytes header
|
||||
vb->append(aud_nal, 4);
|
||||
vb->append((const char*)aud_nal, 4);
|
||||
// pps
|
||||
vb->append(codec->pictureParameterSetNALUnit, codec->pictureParameterSetLength);
|
||||
}
|
||||
|
@ -1318,13 +1318,13 @@ int SrsHlsCache::cache_video(SrsAvcAacCodec* codec, SrsCodecSample* sample)
|
|||
u_int8_t* end = p + 3;
|
||||
|
||||
// first AnnexB prefix is long (4 bytes)
|
||||
if (vb->size == 0) {
|
||||
if (vb->length() == 0) {
|
||||
p = aud_nal;
|
||||
}
|
||||
vb->append(p, end - p);
|
||||
vb->append((const char*)p, end - p);
|
||||
|
||||
// sample data
|
||||
vb->append(buf->bytes, buf->size);
|
||||
vb->append(sample_unit->bytes, sample_unit->size);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -50,9 +50,9 @@ extern int aac_sample_rates[];
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class SrsBuffer;
|
||||
class SrsSharedPtrMessage;
|
||||
class SrsCodecSample;
|
||||
class SrsCodecBuffer;
|
||||
class SrsMpegtsFrame;
|
||||
class SrsAmf0Object;
|
||||
class SrsRtmpJitter;
|
||||
|
@ -109,8 +109,8 @@ public:
|
|||
virtual ~SrsTSMuxer();
|
||||
public:
|
||||
virtual int open(std::string _path);
|
||||
virtual int write_audio(SrsMpegtsFrame* af, SrsCodecBuffer* ab);
|
||||
virtual int write_video(SrsMpegtsFrame* vf, SrsCodecBuffer* vb);
|
||||
virtual int write_audio(SrsMpegtsFrame* af, SrsBuffer* ab);
|
||||
virtual int write_video(SrsMpegtsFrame* vf, SrsBuffer* vb);
|
||||
virtual void close();
|
||||
};
|
||||
|
||||
|
@ -196,8 +196,8 @@ public:
|
|||
* that is whether the current segment duration >= the segment in config
|
||||
*/
|
||||
virtual bool is_segment_overflow();
|
||||
virtual int flush_audio(SrsMpegtsFrame* af, SrsCodecBuffer* ab);
|
||||
virtual int flush_video(SrsMpegtsFrame* af, SrsCodecBuffer* ab, SrsMpegtsFrame* vf, SrsCodecBuffer* vb);
|
||||
virtual int flush_audio(SrsMpegtsFrame* af, SrsBuffer* ab);
|
||||
virtual int flush_video(SrsMpegtsFrame* af, SrsBuffer* ab, SrsMpegtsFrame* vf, SrsBuffer* vb);
|
||||
/**
|
||||
* close segment(ts).
|
||||
* @param log_desc the description for log.
|
||||
|
@ -231,9 +231,9 @@ class SrsHlsCache
|
|||
private:
|
||||
// current frame and buffer
|
||||
SrsMpegtsFrame* af;
|
||||
SrsCodecBuffer* ab;
|
||||
SrsBuffer* ab;
|
||||
SrsMpegtsFrame* vf;
|
||||
SrsCodecBuffer* vb;
|
||||
SrsBuffer* vb;
|
||||
private:
|
||||
// the audio cache buffer start pts, to flush audio if full.
|
||||
int64_t audio_buffer_start_pts;
|
||||
|
|
|
@ -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 "160"
|
||||
#define VERSION_REVISION "161"
|
||||
#define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION
|
||||
// server info.
|
||||
#define RTMP_SIG_SRS_KEY "SRS"
|
||||
|
|
Loading…
Reference in a new issue