winlin

refine hls codec sample info. 0.9.161

... ... @@ -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"
... ...