1
0
Fork 0
mirror of https://github.com/ossrs/srs.git synced 2025-03-09 15:49:59 +00:00

refine hls codec sample info. 0.9.161

This commit is contained in:
winlin 2014-07-15 10:44:06 +08:00
parent f020690ed7
commit a4d3283cdd
5 changed files with 105 additions and 83 deletions

View file

@ -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_codec.hpp>
#include <srs_kernel_stream.hpp> #include <srs_kernel_stream.hpp>
SrsCodecBuffer::SrsCodecBuffer() SrsCodecSampleUnit::SrsCodecSampleUnit()
{ {
size = 0; size = 0;
bytes = NULL; 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() SrsCodecSample::SrsCodecSample()
@ -64,7 +52,7 @@ SrsCodecSample::~SrsCodecSample()
void SrsCodecSample::clear() void SrsCodecSample::clear()
{ {
is_video = false; is_video = false;
nb_buffers = 0; nb_sample_units = 0;
cts = 0; cts = 0;
frame_type = SrsCodecVideoAVCFrameReserved; frame_type = SrsCodecVideoAVCFrameReserved;
@ -76,20 +64,20 @@ void SrsCodecSample::clear()
aac_packet_type = SrsCodecAudioTypeReserved; 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; int ret = ERROR_SUCCESS;
if (nb_buffers >= SRS_MAX_CODEC_SAMPLE) { if (nb_sample_units >= SRS_MAX_CODEC_SAMPLE) {
ret = ERROR_HLS_DECODE_ERROR; ret = ERROR_HLS_DECODE_ERROR;
srs_error("hls decode samples error, " srs_error("hls decode samples error, "
"exceed the max count: %d, ret=%d", SRS_MAX_CODEC_SAMPLE, ret); "exceed the max count: %d, ret=%d", SRS_MAX_CODEC_SAMPLE, ret);
return ret; return ret;
} }
SrsCodecBuffer* buf = &buffers[nb_buffers++]; SrsCodecSampleUnit* sample_unit = &sample_units[nb_sample_units++];
buf->bytes = bytes; sample_unit->bytes = bytes;
buf->size = size; sample_unit->size = size;
return ret; return ret;
} }
@ -239,7 +227,7 @@ int SrsAvcAacCodec::audio_aac_demux(char* data, int size, SrsCodecSample* sample
// Raw AAC frame data in UI8 [] // Raw AAC frame data in UI8 []
// 6.3 Raw Data, aac-iso-13818-7.pdf, page 28 // 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); srs_error("hls add audio sample failed. ret=%d", ret);
return ret; return ret;
} }
@ -445,7 +433,7 @@ int SrsAvcAacCodec::video_avc_demux(char* data, int size, SrsCodecSample* sample
return ret; return ret;
} }
// 7.3.1 NAL unit syntax, H.264-AVC-ISO_IEC_14496-10.pdf, page 44. // 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); srs_error("hls add video sample failed. ret=%d", ret);
return ret; return ret;
} }

View file

@ -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: 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; int size;
char* bytes; char* bytes;
public: public:
SrsCodecBuffer(); SrsCodecSampleUnit();
void append(void* data, int len); virtual ~SrsCodecSampleUnit();
public:
/**
* free the bytes,
* user can invoke it to free the bytes,
* the SrsCodecBuffer never free automatically.
*/
void free();
}; };
/** /**
* the samples in the flv audio/video packet. * 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 class SrsCodecSample
{ {
@ -123,12 +131,14 @@ public:
* generally, aac audio packet corresponding to one buffer, * generally, aac audio packet corresponding to one buffer,
* where avc/h264 video packet may contains multiple buffer. * where avc/h264 video packet may contains multiple buffer.
*/ */
int nb_buffers; int nb_sample_units;
SrsCodecBuffer buffers[SRS_MAX_CODEC_SAMPLE]; SrsCodecSampleUnit sample_units[SRS_MAX_CODEC_SAMPLE];
public: public:
bool is_video; 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; int32_t cts;
public: public:
// video specified // video specified
@ -143,13 +153,37 @@ public:
public: public:
SrsCodecSample(); SrsCodecSample();
virtual ~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(); 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. * 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 class SrsAvcAacCodec
{ {

View file

@ -68,6 +68,7 @@ using namespace std;
#include <srs_kernel_utility.hpp> #include <srs_kernel_utility.hpp>
#include <srs_app_avc_aac.hpp> #include <srs_app_avc_aac.hpp>
#include <srs_kernel_file.hpp> #include <srs_kernel_file.hpp>
#include <srs_kernel_buffer.hpp>
// max PES packets size to flush the video. // max PES packets size to flush the video.
#define SRS_AUTO_HLS_AUDIO_CACHE_SIZE 1024 * 1024 #define SRS_AUTO_HLS_AUDIO_CACHE_SIZE 1024 * 1024
@ -195,16 +196,16 @@ public:
return ret; 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; int ret = ERROR_SUCCESS;
if (!buffer->bytes || buffer->size <= 0) { if (!buffer->bytes() || buffer->length() <= 0) {
return ret; return ret;
} }
char* last = buffer->bytes + buffer->size; char* last = buffer->bytes() + buffer->length();
char* pos = buffer->bytes; char* pos = buffer->bytes();
bool first = true; bool first = true;
while (pos < last) { while (pos < last) {
@ -478,7 +479,7 @@ int SrsTSMuxer::open(string _path)
return ret; return ret;
} }
int SrsTSMuxer::write_audio(SrsMpegtsFrame* af, SrsCodecBuffer* ab) int SrsTSMuxer::write_audio(SrsMpegtsFrame* af, SrsBuffer* ab)
{ {
int ret = ERROR_SUCCESS; int ret = ERROR_SUCCESS;
@ -489,7 +490,7 @@ int SrsTSMuxer::write_audio(SrsMpegtsFrame* af, SrsCodecBuffer* ab)
return ret; return ret;
} }
int SrsTSMuxer::write_video(SrsMpegtsFrame* vf, SrsCodecBuffer* vb) int SrsTSMuxer::write_video(SrsMpegtsFrame* vf, SrsBuffer* vb)
{ {
int ret = ERROR_SUCCESS; int ret = ERROR_SUCCESS;
@ -651,7 +652,7 @@ bool SrsHlsMuxer::is_segment_overflow()
return current->duration >= hls_fragment; 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; int ret = ERROR_SUCCESS;
@ -661,7 +662,7 @@ int SrsHlsMuxer::flush_audio(SrsMpegtsFrame* af, SrsCodecBuffer* ab)
return ret; return ret;
} }
if (ab->size <= 0) { if (ab->length() <= 0) {
return ret; return ret;
} }
@ -673,13 +674,12 @@ int SrsHlsMuxer::flush_audio(SrsMpegtsFrame* af, SrsCodecBuffer* ab)
} }
// write success, clear and free the buffer // write success, clear and free the buffer
ab->free(); ab->erase(ab->length());
return ret; return ret;
} }
int SrsHlsMuxer::flush_video( int SrsHlsMuxer::flush_video(SrsMpegtsFrame* af, SrsBuffer* ab, SrsMpegtsFrame* vf, SrsBuffer* vb)
SrsMpegtsFrame* af, SrsCodecBuffer* ab, SrsMpegtsFrame* vf, SrsCodecBuffer* vb)
{ {
int ret = ERROR_SUCCESS; int ret = ERROR_SUCCESS;
@ -699,7 +699,7 @@ int SrsHlsMuxer::flush_video(
} }
// write success, clear and free the buffer // write success, clear and free the buffer
vb->free(); vb->erase(vb->length());
return ret; return ret;
} }
@ -962,8 +962,8 @@ SrsHlsCache::SrsHlsCache()
{ {
aac_jitter = new SrsHlsAacJitter(); aac_jitter = new SrsHlsAacJitter();
ab = new SrsCodecBuffer(); ab = new SrsBuffer();
vb = new SrsCodecBuffer(); vb = new SrsBuffer();
af = new SrsMpegtsFrame(); af = new SrsMpegtsFrame();
vf = new SrsMpegtsFrame(); vf = new SrsMpegtsFrame();
@ -975,8 +975,8 @@ SrsHlsCache::~SrsHlsCache()
{ {
srs_freep(aac_jitter); srs_freep(aac_jitter);
ab->free(); ab->erase(ab->length());
vb->free(); vb->erase(vb->length());
srs_freep(ab); srs_freep(ab);
srs_freep(vb); srs_freep(vb);
@ -1051,7 +1051,7 @@ int SrsHlsCache::write_audio(SrsAvcAacCodec* codec, SrsHlsMuxer* muxer, int64_t
int ret = ERROR_SUCCESS; int ret = ERROR_SUCCESS;
// start buffer, set the af // 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); pts = aac_jitter->on_buffer_start(pts, sample->sound_rate, codec->aac_sample_rate);
af->dts = af->pts = audio_buffer_start_pts = pts; 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. // 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) { if ((ret = muxer->flush_audio(af, ab)) != ERROR_SUCCESS) {
return ret; return ret;
} }
@ -1159,11 +1159,11 @@ int SrsHlsCache::cache_audio(SrsAvcAacCodec* codec, SrsCodecSample* sample)
{ {
int ret = ERROR_SUCCESS; int ret = ERROR_SUCCESS;
for (int i = 0; i < sample->nb_buffers; i++) { for (int i = 0; i < sample->nb_sample_units; i++) {
SrsCodecBuffer* buf = &sample->buffers[i]; SrsCodecSampleUnit* sample_unit = &sample->sample_units[i];
int32_t size = buf->size; 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; ret = ERROR_HLS_AAC_FRAME_LENGTH;
srs_error("invalid aac frame length=%d, ret=%d", size, ret); srs_error("invalid aac frame length=%d, ret=%d", size, ret);
return ret; return ret;
@ -1215,8 +1215,8 @@ int SrsHlsCache::cache_audio(SrsAvcAacCodec* codec, SrsCodecSample* sample)
adts_header[5] |= 0x1f; adts_header[5] |= 0x1f;
// copy to audio buffer // copy to audio buffer
ab->append(adts_header, sizeof(adts_header)); ab->append((const char*)adts_header, sizeof(adts_header));
ab->append(buf->bytes, buf->size); ab->append(sample_unit->bytes, sample_unit->size);
} }
return ret; return ret;
@ -1239,11 +1239,11 @@ int SrsHlsCache::cache_video(SrsAvcAacCodec* codec, SrsCodecSample* sample)
* xxxxxxx // data bytes. * xxxxxxx // data bytes.
* so, for each sample, we append header in aud_nal, then appends the bytes in sample. * 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++) { for (int i = 0; i < sample->nb_sample_units; i++) {
SrsCodecBuffer* buf = &sample->buffers[i]; SrsCodecSampleUnit* sample_unit = &sample->sample_units[i];
int32_t size = buf->size; int32_t size = sample_unit->size;
if (!buf->bytes || size <= 0) { if (!sample_unit->bytes || size <= 0) {
ret = ERROR_HLS_AVC_SAMPLE_SIZE; ret = ERROR_HLS_AVC_SAMPLE_SIZE;
srs_error("invalid avc sample length=%d, ret=%d", size, ret); srs_error("invalid avc sample length=%d, ret=%d", size, ret);
return ret; return ret;
@ -1259,7 +1259,7 @@ int SrsHlsCache::cache_video(SrsAvcAacCodec* codec, SrsCodecSample* sample)
// 5bits, 7.3.1 NAL unit syntax, // 5bits, 7.3.1 NAL unit syntax,
// H.264-AVC-ISO_IEC_14496-10.pdf, page 44. // H.264-AVC-ISO_IEC_14496-10.pdf, page 44.
u_int8_t nal_unit_type; u_int8_t nal_unit_type;
nal_unit_type = *buf->bytes; nal_unit_type = *sample_unit->bytes;
nal_unit_type &= 0x1f; nal_unit_type &= 0x1f;
// @see: ngx_rtmp_hls_video // @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) { if (nal_unit_type == 1 || nal_unit_type == 5 || nal_unit_type == 6) {
// for type 6, append a aud with type 9. // 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; aud_sent = true;
} }
} }
@ -1290,13 +1290,13 @@ int SrsHlsCache::cache_video(SrsAvcAacCodec* codec, SrsCodecSample* sample)
// @see: ngx_rtmp_hls_append_sps_pps // @see: ngx_rtmp_hls_append_sps_pps
if (codec->sequenceParameterSetLength > 0) { if (codec->sequenceParameterSetLength > 0) {
// AnnexB prefix, for sps always 4 bytes header // AnnexB prefix, for sps always 4 bytes header
vb->append(aud_nal, 4); vb->append((const char*)aud_nal, 4);
// sps // sps
vb->append(codec->sequenceParameterSetNALUnit, codec->sequenceParameterSetLength); vb->append(codec->sequenceParameterSetNALUnit, codec->sequenceParameterSetLength);
} }
if (codec->pictureParameterSetLength > 0) { if (codec->pictureParameterSetLength > 0) {
// AnnexB prefix, for pps always 4 bytes header // AnnexB prefix, for pps always 4 bytes header
vb->append(aud_nal, 4); vb->append((const char*)aud_nal, 4);
// pps // pps
vb->append(codec->pictureParameterSetNALUnit, codec->pictureParameterSetLength); vb->append(codec->pictureParameterSetNALUnit, codec->pictureParameterSetLength);
} }
@ -1318,13 +1318,13 @@ int SrsHlsCache::cache_video(SrsAvcAacCodec* codec, SrsCodecSample* sample)
u_int8_t* end = p + 3; u_int8_t* end = p + 3;
// first AnnexB prefix is long (4 bytes) // first AnnexB prefix is long (4 bytes)
if (vb->size == 0) { if (vb->length() == 0) {
p = aud_nal; p = aud_nal;
} }
vb->append(p, end - p); vb->append((const char*)p, end - p);
// sample data // sample data
vb->append(buf->bytes, buf->size); vb->append(sample_unit->bytes, sample_unit->size);
} }
return ret; return ret;

View file

@ -50,9 +50,9 @@ extern int aac_sample_rates[];
#include <string> #include <string>
#include <vector> #include <vector>
class SrsBuffer;
class SrsSharedPtrMessage; class SrsSharedPtrMessage;
class SrsCodecSample; class SrsCodecSample;
class SrsCodecBuffer;
class SrsMpegtsFrame; class SrsMpegtsFrame;
class SrsAmf0Object; class SrsAmf0Object;
class SrsRtmpJitter; class SrsRtmpJitter;
@ -109,8 +109,8 @@ public:
virtual ~SrsTSMuxer(); virtual ~SrsTSMuxer();
public: public:
virtual int open(std::string _path); virtual int open(std::string _path);
virtual int write_audio(SrsMpegtsFrame* af, SrsCodecBuffer* ab); virtual int write_audio(SrsMpegtsFrame* af, SrsBuffer* ab);
virtual int write_video(SrsMpegtsFrame* vf, SrsCodecBuffer* vb); virtual int write_video(SrsMpegtsFrame* vf, SrsBuffer* vb);
virtual void close(); virtual void close();
}; };
@ -196,8 +196,8 @@ public:
* that is whether the current segment duration >= the segment in config * that is whether the current segment duration >= the segment in config
*/ */
virtual bool is_segment_overflow(); virtual bool is_segment_overflow();
virtual int flush_audio(SrsMpegtsFrame* af, SrsCodecBuffer* ab); virtual int flush_audio(SrsMpegtsFrame* af, SrsBuffer* ab);
virtual int flush_video(SrsMpegtsFrame* af, SrsCodecBuffer* ab, SrsMpegtsFrame* vf, SrsCodecBuffer* vb); virtual int flush_video(SrsMpegtsFrame* af, SrsBuffer* ab, SrsMpegtsFrame* vf, SrsBuffer* vb);
/** /**
* close segment(ts). * close segment(ts).
* @param log_desc the description for log. * @param log_desc the description for log.
@ -231,9 +231,9 @@ class SrsHlsCache
private: private:
// current frame and buffer // current frame and buffer
SrsMpegtsFrame* af; SrsMpegtsFrame* af;
SrsCodecBuffer* ab; SrsBuffer* ab;
SrsMpegtsFrame* vf; SrsMpegtsFrame* vf;
SrsCodecBuffer* vb; SrsBuffer* vb;
private: private:
// the audio cache buffer start pts, to flush audio if full. // the audio cache buffer start pts, to flush audio if full.
int64_t audio_buffer_start_pts; int64_t audio_buffer_start_pts;

View file

@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// current release version // current release version
#define VERSION_MAJOR "0" #define VERSION_MAJOR "0"
#define VERSION_MINOR "9" #define VERSION_MINOR "9"
#define VERSION_REVISION "160" #define VERSION_REVISION "161"
#define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION #define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION
// server info. // server info.
#define RTMP_SIG_SRS_KEY "SRS" #define RTMP_SIG_SRS_KEY "SRS"