mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
For #299, refine the codec to format-frame-sample chain.
This commit is contained in:
parent
c4a510b834
commit
d7458c4e72
18 changed files with 990 additions and 1150 deletions
|
@ -93,7 +93,6 @@ int SrsAacEncoder::write_audio(int64_t timestamp, char* data, int size)
|
|||
// @see: E.4.2 Audio Tags, video_file_format_spec_v10_1.pdf, page 76
|
||||
int8_t sound_format = stream->read_1bytes();
|
||||
|
||||
// @see: SrsAvcAacCodec::audio_aac_demux
|
||||
//int8_t sound_type = sound_format & 0x01;
|
||||
//int8_t sound_size = (sound_format >> 1) & 0x01;
|
||||
//int8_t sound_rate = (sound_format >> 2) & 0x03;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -201,7 +201,6 @@ enum SrsCodecFlvTag
|
|||
|
||||
/**
|
||||
* Annex E. The FLV File Format
|
||||
* @see SrsAvcAacCodec for the media stream codec.
|
||||
*/
|
||||
class SrsFlvCodec
|
||||
{
|
||||
|
@ -375,6 +374,7 @@ std::string srs_codec_aac_profile2str(SrsAacProfile aac_profile);
|
|||
enum SrsAacObjectType
|
||||
{
|
||||
SrsAacObjectTypeReserved = 0,
|
||||
SrsAacObjectTypeForbidden = 0,
|
||||
|
||||
// Table 1.1 - Audio Object Type definition
|
||||
// @see @see ISO_IEC_14496-3-AAC-2001.pdf, page 23
|
||||
|
@ -454,9 +454,9 @@ class SrsSample
|
|||
{
|
||||
public:
|
||||
// The size of unit.
|
||||
int nb_unit;
|
||||
int size;
|
||||
// The ptr of unit, user must manage it.
|
||||
char* unit;
|
||||
char* bytes;
|
||||
public:
|
||||
SrsSample();
|
||||
virtual ~SrsSample();
|
||||
|
@ -472,9 +472,6 @@ class SrsCodec
|
|||
public:
|
||||
SrsCodec();
|
||||
virtual ~SrsCodec();
|
||||
public:
|
||||
// Get the codec type.
|
||||
virtual SrsCodecFlvTag codec() = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -484,17 +481,41 @@ class SrsAudioCodec : public SrsCodec
|
|||
{
|
||||
public:
|
||||
// audio specified
|
||||
SrsCodecAudio acodec;
|
||||
SrsCodecAudio id;
|
||||
// audio aac specified.
|
||||
SrsCodecAudioSampleRate sound_rate;
|
||||
SrsCodecAudioSampleSize sound_size;
|
||||
SrsCodecAudioSoundType sound_type;
|
||||
SrsCodecAudioType aac_packet_type;
|
||||
int audio_data_rate; // in bps
|
||||
public:
|
||||
/**
|
||||
* audio specified
|
||||
* audioObjectType, in 1.6.2.1 AudioSpecificConfig, page 33,
|
||||
* 1.5.1.1 Audio object type definition, page 23,
|
||||
* in ISO_IEC_14496-3-AAC-2001.pdf.
|
||||
*/
|
||||
SrsAacObjectType aac_object;
|
||||
/**
|
||||
* samplingFrequencyIndex
|
||||
*/
|
||||
uint8_t aac_sample_rate;
|
||||
/**
|
||||
* channelConfiguration
|
||||
*/
|
||||
uint8_t aac_channels;
|
||||
public:
|
||||
/**
|
||||
* the aac extra data, the AAC sequence header,
|
||||
* without the flv codec header,
|
||||
* @see: ffmpeg, AVCodecContext::extradata
|
||||
*/
|
||||
int aac_extra_size;
|
||||
char* aac_extra_data;
|
||||
public:
|
||||
SrsAudioCodec();
|
||||
virtual ~SrsAudioCodec();
|
||||
public:
|
||||
virtual SrsCodecFlvTag codec();
|
||||
virtual bool is_aac_codec_ok();
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -503,29 +524,54 @@ public:
|
|||
class SrsVideoCodec : public SrsCodec
|
||||
{
|
||||
public:
|
||||
// video specified
|
||||
SrsCodecVideoAVCFrame frame_type;
|
||||
SrsCodecVideoAVCType avc_packet_type;
|
||||
// whether sample_units contains IDR frame.
|
||||
bool has_idr;
|
||||
// Whether exists AUD NALU.
|
||||
bool has_aud;
|
||||
// Whether exists SPS/PPS NALU.
|
||||
bool has_sps_pps;
|
||||
// The first nalu type.
|
||||
SrsAvcNaluType first_nalu_type;
|
||||
SrsCodecVideo id;
|
||||
int video_data_rate; // in bps
|
||||
double frame_rate;
|
||||
double duration;
|
||||
int width;
|
||||
int height;
|
||||
public:
|
||||
/**
|
||||
* the avc extra data, the AVC sequence header,
|
||||
* without the flv codec header,
|
||||
* @see: ffmpeg, AVCodecContext::extradata
|
||||
*/
|
||||
int avc_extra_size;
|
||||
char* avc_extra_data;
|
||||
public:
|
||||
/**
|
||||
* video specified
|
||||
*/
|
||||
// profile_idc, ISO_IEC_14496-10-AVC-2003.pdf, page 45.
|
||||
SrsAvcProfile avc_profile;
|
||||
// level_idc, ISO_IEC_14496-10-AVC-2003.pdf, page 45.
|
||||
SrsAvcLevel avc_level;
|
||||
// lengthSizeMinusOne, ISO_IEC_14496-15-AVC-format-2012.pdf, page 16
|
||||
int8_t NAL_unit_length;
|
||||
uint16_t sequenceParameterSetLength;
|
||||
char* sequenceParameterSetNALUnit;
|
||||
uint16_t pictureParameterSetLength;
|
||||
char* pictureParameterSetNALUnit;
|
||||
public:
|
||||
// the avc payload format.
|
||||
SrsAvcPayloadFormat payload_format;
|
||||
public:
|
||||
SrsVideoCodec();
|
||||
virtual ~SrsVideoCodec();
|
||||
public:
|
||||
virtual SrsCodecFlvTag codec();
|
||||
virtual bool is_avc_codec_ok();
|
||||
};
|
||||
|
||||
/**
|
||||
* A codec frame, consists of a codec and a group of samples.
|
||||
* A frame, consists of a codec and a group of samples.
|
||||
*/
|
||||
class SrsFrame
|
||||
{
|
||||
public:
|
||||
// The DTS/PTS in milliseconds, which is TBN=1000.
|
||||
int64_t dts;
|
||||
// PTS = DTS + CTS.
|
||||
int32_t cts;
|
||||
public:
|
||||
// The codec info of frame.
|
||||
SrsCodec* codec;
|
||||
|
@ -536,43 +582,32 @@ public:
|
|||
public:
|
||||
SrsFrame();
|
||||
virtual ~SrsFrame();
|
||||
public:
|
||||
// Initialize the frame, to parse sampels.
|
||||
virtual int initialize(SrsCodec* c);
|
||||
// Add a sample to frame.
|
||||
virtual int add_sample(char* bytes, int size);
|
||||
};
|
||||
|
||||
/**
|
||||
* 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
|
||||
* A audio frame, besides a frame, contains the audio frame info, such as frame type.
|
||||
*/
|
||||
class SrsAudioFrame : public SrsFrame
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* each audio/video raw data packet will dumps to one or multiple buffers,
|
||||
* the buffers will write to hls and clear to reset.
|
||||
* generally, aac audio packet corresponding to one buffer,
|
||||
* where avc/h264 video packet may contains multiple buffer.
|
||||
*/
|
||||
int nb_sample_units;
|
||||
SrsCodecSampleUnit sample_units[SRS_MAX_CODEC_SAMPLE];
|
||||
SrsCodecAudioType aac_packet_type;
|
||||
public:
|
||||
/**
|
||||
* whether the sample is video sample which demux from video packet.
|
||||
*/
|
||||
bool is_video;
|
||||
/**
|
||||
* CompositionTime, video_file_format_spec_v10_1.pdf, page 78.
|
||||
* cts = pts - dts, where dts = flvheader->timestamp.
|
||||
*/
|
||||
int32_t cts;
|
||||
SrsAudioFrame();
|
||||
virtual ~SrsAudioFrame();
|
||||
public:
|
||||
virtual SrsAudioCodec* acodec();
|
||||
};
|
||||
|
||||
/**
|
||||
* A video frame, besides a frame, contains the video frame info, such as frame type.
|
||||
*/
|
||||
class SrsVideoFrame : public SrsFrame
|
||||
{
|
||||
public:
|
||||
// video specified
|
||||
SrsCodecVideoAVCFrame frame_type;
|
||||
|
@ -586,171 +621,74 @@ public:
|
|||
// The first nalu type.
|
||||
SrsAvcNaluType first_nalu_type;
|
||||
public:
|
||||
// audio specified
|
||||
SrsCodecAudio acodec;
|
||||
// audio aac specified.
|
||||
SrsCodecAudioSampleRate sound_rate;
|
||||
SrsCodecAudioSampleSize sound_size;
|
||||
SrsCodecAudioSoundType sound_type;
|
||||
SrsCodecAudioType aac_packet_type;
|
||||
SrsVideoFrame();
|
||||
virtual ~SrsVideoFrame();
|
||||
public:
|
||||
SrsCodecSample();
|
||||
virtual ~SrsCodecSample();
|
||||
// Add the sample without ANNEXB or IBMF header, or RAW AAC or MP3 data.
|
||||
virtual int add_sample(char* bytes, int size);
|
||||
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();
|
||||
/**
|
||||
* 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);
|
||||
virtual SrsVideoCodec* vcodec();
|
||||
};
|
||||
|
||||
/**
|
||||
* the h264/avc and aac codec, for media stream.
|
||||
*
|
||||
* 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
|
||||
* A codec format, including one or many stream, each stream identified by a frame.
|
||||
* For example, a typical RTMP stream format, consits of a video and audio frame.
|
||||
* Maybe some RTMP stream only has a audio stream, for instance, redio application.
|
||||
*/
|
||||
class SrsFormat
|
||||
{
|
||||
private:
|
||||
SrsBuffer* stream;
|
||||
public:
|
||||
/**
|
||||
* metadata specified
|
||||
*/
|
||||
int duration;
|
||||
int width;
|
||||
int height;
|
||||
int frame_rate;
|
||||
// @see: SrsCodecVideo
|
||||
int video_codec_id;
|
||||
int video_data_rate; // in bps
|
||||
// @see: SrsCod ecAudioType
|
||||
int audio_codec_id;
|
||||
int audio_data_rate; // in bps
|
||||
public:
|
||||
/**
|
||||
* video specified
|
||||
*/
|
||||
// profile_idc, ISO_IEC_14496-10-AVC-2003.pdf, page 45.
|
||||
SrsAvcProfile avc_profile;
|
||||
// level_idc, ISO_IEC_14496-10-AVC-2003.pdf, page 45.
|
||||
SrsAvcLevel avc_level;
|
||||
// lengthSizeMinusOne, ISO_IEC_14496-15-AVC-format-2012.pdf, page 16
|
||||
int8_t NAL_unit_length;
|
||||
uint16_t sequenceParameterSetLength;
|
||||
char* sequenceParameterSetNALUnit;
|
||||
uint16_t pictureParameterSetLength;
|
||||
char* pictureParameterSetNALUnit;
|
||||
private:
|
||||
// the avc payload format.
|
||||
SrsAvcPayloadFormat payload_format;
|
||||
public:
|
||||
/**
|
||||
* audio specified
|
||||
* audioObjectType, in 1.6.2.1 AudioSpecificConfig, page 33,
|
||||
* 1.5.1.1 Audio object type definition, page 23,
|
||||
* in ISO_IEC_14496-3-AAC-2001.pdf.
|
||||
*/
|
||||
SrsAacObjectType aac_object;
|
||||
/**
|
||||
* samplingFrequencyIndex
|
||||
*/
|
||||
uint8_t aac_sample_rate;
|
||||
/**
|
||||
* channelConfiguration
|
||||
*/
|
||||
uint8_t aac_channels;
|
||||
public:
|
||||
/**
|
||||
* the avc extra data, the AVC sequence header,
|
||||
* without the flv codec header,
|
||||
* @see: ffmpeg, AVCodecContext::extradata
|
||||
*/
|
||||
int avc_extra_size;
|
||||
char* avc_extra_data;
|
||||
/**
|
||||
* the aac extra data, the AAC sequence header,
|
||||
* without the flv codec header,
|
||||
* @see: ffmpeg, AVCodecContext::extradata
|
||||
*/
|
||||
int aac_extra_size;
|
||||
char* aac_extra_data;
|
||||
SrsAudioFrame* audio;
|
||||
SrsAudioCodec* acodec;
|
||||
SrsVideoFrame* video;
|
||||
SrsVideoCodec* vcodec;
|
||||
SrsBuffer* buffer;
|
||||
public:
|
||||
// for sequence header, whether parse the h.264 sps.
|
||||
// TODO: FIXME: Refine it.
|
||||
bool avc_parse_sps;
|
||||
public:
|
||||
SrsAvcAacCodec();
|
||||
virtual ~SrsAvcAacCodec();
|
||||
SrsFormat();
|
||||
virtual ~SrsFormat();
|
||||
public:
|
||||
// whether avc or aac codec sequence header or extra data is decoded ok.
|
||||
virtual bool is_avc_codec_ok();
|
||||
virtual bool is_aac_codec_ok();
|
||||
// the following function used for hls to build the sample and codec.
|
||||
// Initialize the format.
|
||||
virtual int initialize();
|
||||
// When got a parsed audio packet.
|
||||
virtual int on_audio(int64_t timestamp, char* data, int size);
|
||||
// When got a parsed video packet.
|
||||
virtual int on_video(int64_t timestamp, char* data, int size);
|
||||
// When got a audio aac sequence header.
|
||||
virtual int on_aac_sequence_header(char* data, int size);
|
||||
public:
|
||||
/**
|
||||
* demux the audio packet in aac codec.
|
||||
* the packet mux in FLV/RTMP format defined in flv specification.
|
||||
* demux the audio speicified data(sound_format, sound_size, ...) to sample.
|
||||
* demux the aac specified data(aac_profile, ...) to codec from sequence header.
|
||||
* demux the aac raw to sample units.
|
||||
*/
|
||||
virtual int audio_aac_demux(char* data, int size, SrsCodecSample* sample);
|
||||
virtual int audio_mp3_demux(char* data, int size, SrsCodecSample* sample);
|
||||
/**
|
||||
* demux the video packet in h.264 codec.
|
||||
* the packet mux in FLV/RTMP format defined in flv specification.
|
||||
* demux the video specified data(frame_type, codec_id, ...) to sample.
|
||||
* demux the h.264 sepcified data(avc_profile, ...) to codec from sequence header.
|
||||
* demux the h.264 NALUs to sampe units.
|
||||
*/
|
||||
virtual int video_avc_demux(char* data, int size, SrsCodecSample* sample);
|
||||
virtual bool is_aac_sequence_header();
|
||||
virtual bool is_avc_sequence_header();
|
||||
private:
|
||||
virtual int video_nalu_demux(SrsBuffer* stream, SrsCodecSample* sample);
|
||||
public:
|
||||
/**
|
||||
* directly demux the sequence header, without RTMP packet header.
|
||||
*/
|
||||
virtual int audio_aac_sequence_header_demux(char* data, int size);
|
||||
// Demux the video packet in H.264 codec.
|
||||
// The packet is muxed in FLV format, defined in flv specification.
|
||||
// Demux the sps/pps from sequence header.
|
||||
// Demux the samples from NALUs.
|
||||
virtual int video_avc_demux(SrsBuffer* stream, int64_t timestamp);
|
||||
private:
|
||||
/**
|
||||
* when avc packet type is SrsCodecVideoAVCTypeSequenceHeader,
|
||||
* decode the sps and pps.
|
||||
*/
|
||||
// Parse the H.264 SPS/PPS.
|
||||
virtual int avc_demux_sps_pps(SrsBuffer* stream);
|
||||
/**
|
||||
* decode the sps rbsp stream.
|
||||
*/
|
||||
virtual int avc_demux_sps();
|
||||
virtual int avc_demux_sps_rbsp(char* rbsp, int nb_rbsp);
|
||||
/**
|
||||
* demux the avc NALU in "AnnexB"
|
||||
* from ISO_IEC_14496-10-AVC-2003.pdf, page 211.
|
||||
*/
|
||||
virtual int avc_demux_annexb_format(SrsBuffer* stream, SrsCodecSample* sample);
|
||||
/**
|
||||
* demux the avc NALU in "ISO Base Media File Format"
|
||||
* from ISO_IEC_14496-15-AVC-format-2012.pdf, page 20
|
||||
*/
|
||||
virtual int avc_demux_ibmf_format(SrsBuffer* stream, SrsCodecSample* sample);
|
||||
private:
|
||||
// Parse the H.264 NALUs.
|
||||
virtual int video_nalu_demux(SrsBuffer* stream);
|
||||
// Demux the avc NALU in "AnnexB" from ISO_IEC_14496-10-AVC-2003.pdf, page 211.
|
||||
virtual int avc_demux_annexb_format(SrsBuffer* stream);
|
||||
// Demux the avc NALU in "ISO Base Media File Format" from ISO_IEC_14496-15-AVC-format-2012.pdf, page 20
|
||||
virtual int avc_demux_ibmf_format(SrsBuffer* stream);
|
||||
private:
|
||||
// Demux the audio packet in AAC codec.
|
||||
// Demux the asc from sequence header.
|
||||
// Demux the sampels from RAW data.
|
||||
virtual int audio_aac_demux(SrsBuffer* stream, int64_t timestamp);
|
||||
virtual int audio_mp3_demux(SrsBuffer* stream, int64_t timestamp);
|
||||
public:
|
||||
// Directly demux the sequence header, without RTMP packet header.
|
||||
virtual int audio_aac_sequence_header_demux(char* data, int size);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -106,7 +106,6 @@ int SrsMp3Encoder::write_audio(int64_t timestamp, char* data, int size)
|
|||
// @see: E.4.2 Audio Tags, video_file_format_spec_v10_1.pdf, page 76
|
||||
int8_t sound_format = stream->read_1bytes();
|
||||
|
||||
// @see: SrsAvcAacCodec::audio_aac_demux
|
||||
//int8_t sound_type = sound_format & 0x01;
|
||||
//int8_t sound_size = (sound_format >> 1) & 0x01;
|
||||
//int8_t sound_rate = (sound_format >> 2) & 0x03;
|
||||
|
|
|
@ -2708,7 +2708,7 @@ int SrsTsPayloadPMT::psi_encode(SrsBuffer* stream)
|
|||
return ret;
|
||||
}
|
||||
|
||||
SrsTSMuxer::SrsTSMuxer(SrsFileWriter* w, SrsTsContext* c, SrsCodecAudio ac, SrsCodecVideo vc)
|
||||
SrsTsMuxer::SrsTsMuxer(SrsFileWriter* w, SrsTsContext* c, SrsCodecAudio ac, SrsCodecVideo vc)
|
||||
{
|
||||
writer = w;
|
||||
context = c;
|
||||
|
@ -2717,12 +2717,12 @@ SrsTSMuxer::SrsTSMuxer(SrsFileWriter* w, SrsTsContext* c, SrsCodecAudio ac, SrsC
|
|||
vcodec = vc;
|
||||
}
|
||||
|
||||
SrsTSMuxer::~SrsTSMuxer()
|
||||
SrsTsMuxer::~SrsTsMuxer()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
int SrsTSMuxer::open(string p)
|
||||
int SrsTsMuxer::open(string p)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
|
@ -2740,13 +2740,13 @@ int SrsTSMuxer::open(string p)
|
|||
return ret;
|
||||
}
|
||||
|
||||
int SrsTSMuxer::update_acodec(SrsCodecAudio ac)
|
||||
int SrsTsMuxer::update_acodec(SrsCodecAudio ac)
|
||||
{
|
||||
acodec = ac;
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int SrsTSMuxer::write_audio(SrsTsMessage* audio)
|
||||
int SrsTsMuxer::write_audio(SrsTsMessage* audio)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
|
@ -2762,7 +2762,7 @@ int SrsTSMuxer::write_audio(SrsTsMessage* audio)
|
|||
return ret;
|
||||
}
|
||||
|
||||
int SrsTSMuxer::write_video(SrsTsMessage* video)
|
||||
int SrsTsMuxer::write_video(SrsTsMessage* video)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
|
@ -2778,12 +2778,12 @@ int SrsTSMuxer::write_video(SrsTsMessage* video)
|
|||
return ret;
|
||||
}
|
||||
|
||||
void SrsTSMuxer::close()
|
||||
void SrsTsMuxer::close()
|
||||
{
|
||||
writer->close();
|
||||
}
|
||||
|
||||
SrsCodecVideo SrsTSMuxer::video_codec()
|
||||
SrsCodecVideo SrsTsMuxer::video_codec()
|
||||
{
|
||||
return vcodec;
|
||||
}
|
||||
|
@ -2800,7 +2800,7 @@ SrsTsCache::~SrsTsCache()
|
|||
srs_freep(video);
|
||||
}
|
||||
|
||||
int SrsTsCache::cache_audio(SrsAvcAacCodec* codec, int64_t dts, SrsCodecSample* sample)
|
||||
int SrsTsCache::cache_audio(SrsAudioFrame* frame, int64_t dts)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
|
@ -2817,16 +2817,16 @@ int SrsTsCache::cache_audio(SrsAvcAacCodec* codec, int64_t dts, SrsCodecSample*
|
|||
audio->sid = SrsTsPESStreamIdAudioCommon;
|
||||
|
||||
// must be aac or mp3
|
||||
SrsCodecAudio acodec = (SrsCodecAudio)codec->audio_codec_id;
|
||||
srs_assert(acodec == SrsCodecAudioAAC || acodec == SrsCodecAudioMP3);
|
||||
SrsAudioCodec* acodec = frame->acodec();
|
||||
srs_assert(acodec->id == SrsCodecAudioAAC || acodec->id == SrsCodecAudioMP3);
|
||||
|
||||
// write video to cache.
|
||||
if (codec->audio_codec_id == SrsCodecAudioAAC) {
|
||||
if ((ret = do_cache_aac(codec, sample)) != ERROR_SUCCESS) {
|
||||
if (acodec->id == SrsCodecAudioAAC) {
|
||||
if ((ret = do_cache_aac(frame)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
if ((ret = do_cache_mp3(codec, sample)) != ERROR_SUCCESS) {
|
||||
if ((ret = do_cache_mp3(frame)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
@ -2834,52 +2834,55 @@ int SrsTsCache::cache_audio(SrsAvcAacCodec* codec, int64_t dts, SrsCodecSample*
|
|||
return ret;
|
||||
}
|
||||
|
||||
int SrsTsCache::cache_video(SrsAvcAacCodec* codec, int64_t dts, SrsCodecSample* sample)
|
||||
int SrsTsCache::cache_video(SrsVideoFrame* frame, int64_t dts)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
// create the ts video message.
|
||||
if (!video) {
|
||||
video = new SrsTsMessage();
|
||||
video->write_pcr = sample->frame_type == SrsCodecVideoAVCFrameKeyFrame;
|
||||
video->write_pcr = (frame->frame_type == SrsCodecVideoAVCFrameKeyFrame);
|
||||
video->start_pts = dts;
|
||||
}
|
||||
|
||||
video->dts = dts;
|
||||
video->pts = video->dts + sample->cts * 90;
|
||||
video->pts = video->dts + frame->cts * 90;
|
||||
video->sid = SrsTsPESStreamIdVideoCommon;
|
||||
|
||||
// write video to cache.
|
||||
if ((ret = do_cache_avc(codec, sample)) != ERROR_SUCCESS) {
|
||||
if ((ret = do_cache_avc(frame)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsTsCache::do_cache_mp3(SrsAvcAacCodec* codec, SrsCodecSample* sample)
|
||||
int SrsTsCache::do_cache_mp3(SrsAudioFrame* frame)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
// for mp3, directly write to cache.
|
||||
// TODO: FIXME: implements the ts jitter.
|
||||
for (int i = 0; i < sample->nb_sample_units; i++) {
|
||||
SrsCodecSampleUnit* sample_unit = &sample->sample_units[i];
|
||||
audio->payload->append(sample_unit->bytes, sample_unit->size);
|
||||
for (int i = 0; i < frame->nb_samples; i++) {
|
||||
SrsSample* sample = &frame->samples[i];
|
||||
audio->payload->append(sample->bytes, sample->size);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsTsCache::do_cache_aac(SrsAvcAacCodec* codec, SrsCodecSample* sample)
|
||||
int SrsTsCache::do_cache_aac(SrsAudioFrame* frame)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
for (int i = 0; i < sample->nb_sample_units; i++) {
|
||||
SrsCodecSampleUnit* sample_unit = &sample->sample_units[i];
|
||||
int32_t size = sample_unit->size;
|
||||
SrsAudioCodec* codec = frame->acodec();
|
||||
srs_assert(codec);
|
||||
|
||||
for (int i = 0; i < frame->nb_samples; i++) {
|
||||
SrsSample* sample = &frame->samples[i];
|
||||
int32_t size = sample->size;
|
||||
|
||||
if (!sample_unit->bytes || size <= 0 || size > 0x1fff) {
|
||||
if (!sample->bytes || size <= 0 || size > 0x1fff) {
|
||||
ret = ERROR_HLS_AAC_FRAME_LENGTH;
|
||||
srs_error("invalid aac frame length=%d, ret=%d", size, ret);
|
||||
return ret;
|
||||
|
@ -2933,7 +2936,7 @@ int SrsTsCache::do_cache_aac(SrsAvcAacCodec* codec, SrsCodecSample* sample)
|
|||
|
||||
// copy to audio buffer
|
||||
audio->payload->append((const char*)adts_header, sizeof(adts_header));
|
||||
audio->payload->append(sample_unit->bytes, sample_unit->size);
|
||||
audio->payload->append(sample->bytes, sample->size);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -2995,7 +2998,7 @@ void srs_avc_insert_aud(SrsSimpleStream* payload, bool& aud_inserted)
|
|||
}
|
||||
}
|
||||
|
||||
int SrsTsCache::do_cache_avc(SrsAvcAacCodec* codec, SrsCodecSample* sample)
|
||||
int SrsTsCache::do_cache_avc(SrsVideoFrame* frame)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
|
@ -3003,7 +3006,7 @@ int SrsTsCache::do_cache_avc(SrsAvcAacCodec* codec, SrsCodecSample* sample)
|
|||
bool aud_inserted = false;
|
||||
|
||||
// Insert a default AUD NALU when no AUD in samples.
|
||||
if (!sample->has_aud) {
|
||||
if (!frame->has_aud) {
|
||||
// the aud(access unit delimiter) before each frame.
|
||||
// 7.3.2.4 Access unit delimiter RBSP syntax
|
||||
// ISO_IEC_14496-10-AVC-2012.pdf, page 66.
|
||||
|
@ -3039,12 +3042,15 @@ int SrsTsCache::do_cache_avc(SrsAvcAacCodec* codec, SrsCodecSample* sample)
|
|||
video->payload->append((const char*)default_aud_nalu, 2);
|
||||
}
|
||||
|
||||
SrsVideoCodec* codec = frame->vcodec();
|
||||
srs_assert(codec);
|
||||
|
||||
// all sample use cont nalu header, except the sps-pps before IDR frame.
|
||||
for (int i = 0; i < sample->nb_sample_units; i++) {
|
||||
SrsCodecSampleUnit* sample_unit = &sample->sample_units[i];
|
||||
int32_t size = sample_unit->size;
|
||||
for (int i = 0; i < frame->nb_samples; i++) {
|
||||
SrsSample* sample = &frame->samples[i];
|
||||
int32_t size = sample->size;
|
||||
|
||||
if (!sample_unit->bytes || size <= 0) {
|
||||
if (!sample->bytes || size <= 0) {
|
||||
ret = ERROR_HLS_AVC_SAMPLE_SIZE;
|
||||
srs_error("invalid avc sample length=%d, ret=%d", size, ret);
|
||||
return ret;
|
||||
|
@ -3052,11 +3058,11 @@ int SrsTsCache::do_cache_avc(SrsAvcAacCodec* codec, SrsCodecSample* sample)
|
|||
|
||||
// 5bits, 7.3.1 NAL unit syntax,
|
||||
// ISO_IEC_14496-10-AVC-2012.pdf, page 83.
|
||||
SrsAvcNaluType nal_unit_type = (SrsAvcNaluType)(sample_unit->bytes[0] & 0x1f);
|
||||
SrsAvcNaluType nal_unit_type = (SrsAvcNaluType)(sample->bytes[0] & 0x1f);
|
||||
|
||||
// Insert sps/pps before IDR when there is no sps/pps in samples.
|
||||
// The sps/pps is parsed from sequence header(generally the first flv packet).
|
||||
if (nal_unit_type == SrsAvcNaluTypeIDR && !sample->has_sps_pps) {
|
||||
if (nal_unit_type == SrsAvcNaluTypeIDR && !frame->has_sps_pps) {
|
||||
if (codec->sequenceParameterSetLength > 0) {
|
||||
srs_avc_insert_aud(video->payload, aud_inserted);
|
||||
video->payload->append(codec->sequenceParameterSetNALUnit, codec->sequenceParameterSetLength);
|
||||
|
@ -3069,7 +3075,7 @@ int SrsTsCache::do_cache_avc(SrsAvcAacCodec* codec, SrsCodecSample* sample)
|
|||
|
||||
// Insert the NALU to video in annexb.
|
||||
srs_avc_insert_aud(video->payload, aud_inserted);
|
||||
video->payload->append(sample_unit->bytes, sample_unit->size);
|
||||
video->payload->append(sample->bytes, sample->size);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -3078,8 +3084,7 @@ int SrsTsCache::do_cache_avc(SrsAvcAacCodec* codec, SrsCodecSample* sample)
|
|||
SrsTsEncoder::SrsTsEncoder()
|
||||
{
|
||||
writer = NULL;
|
||||
codec = new SrsAvcAacCodec();
|
||||
sample = new SrsCodecSample();
|
||||
format = new SrsFormat();
|
||||
cache = new SrsTsCache();
|
||||
context = new SrsTsContext();
|
||||
muxer = NULL;
|
||||
|
@ -3087,8 +3092,7 @@ SrsTsEncoder::SrsTsEncoder()
|
|||
|
||||
SrsTsEncoder::~SrsTsEncoder()
|
||||
{
|
||||
srs_freep(codec);
|
||||
srs_freep(sample);
|
||||
srs_freep(format);
|
||||
srs_freep(cache);
|
||||
srs_freep(muxer);
|
||||
srs_freep(context);
|
||||
|
@ -3098,6 +3102,10 @@ int SrsTsEncoder::initialize(SrsFileWriter* fw)
|
|||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
if ((ret = format->initialize()) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
srs_assert(fw);
|
||||
|
||||
if (!fw->is_open()) {
|
||||
|
@ -3109,7 +3117,7 @@ int SrsTsEncoder::initialize(SrsFileWriter* fw)
|
|||
writer = fw;
|
||||
|
||||
srs_freep(muxer);
|
||||
muxer = new SrsTSMuxer(fw, context, SrsCodecAudioAAC, SrsCodecVideoAVC);
|
||||
muxer = new SrsTsMuxer(fw, context, SrsCodecAudioAAC, SrsCodecVideoAVC);
|
||||
|
||||
if ((ret = muxer->open("")) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
|
@ -3122,32 +3130,24 @@ int SrsTsEncoder::write_audio(int64_t timestamp, char* data, int size)
|
|||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
sample->clear();
|
||||
if ((ret = codec->audio_aac_demux(data, size, sample)) != ERROR_SUCCESS) {
|
||||
if (ret != ERROR_HLS_TRY_MP3) {
|
||||
srs_error("http: ts aac demux audio failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
if ((ret = codec->audio_mp3_demux(data, size, sample)) != ERROR_SUCCESS) {
|
||||
srs_error("http: ts mp3 demux audio failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
if ((ret = format->on_audio(timestamp, data, size)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
SrsCodecAudio acodec = (SrsCodecAudio)codec->audio_codec_id;
|
||||
|
||||
// ts support audio codec: aac/mp3
|
||||
if (acodec != SrsCodecAudioAAC && acodec != SrsCodecAudioMP3) {
|
||||
srs_assert(format->acodec && format->audio);
|
||||
if (format->acodec->id != SrsCodecAudioAAC && format->acodec->id != SrsCodecAudioMP3) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// when codec changed, write new header.
|
||||
if ((ret = muxer->update_acodec(acodec)) != ERROR_SUCCESS) {
|
||||
if ((ret = muxer->update_acodec(format->acodec->id)) != ERROR_SUCCESS) {
|
||||
srs_error("http: ts audio write header failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// for aac: ignore sequence header
|
||||
if (acodec == SrsCodecAudioAAC && sample->aac_packet_type == SrsCodecAudioTypeSequenceHeader) {
|
||||
if (format->acodec->id == SrsCodecAudioAAC && format->audio->aac_packet_type == SrsCodecAudioTypeSequenceHeader) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -3157,7 +3157,7 @@ int SrsTsEncoder::write_audio(int64_t timestamp, char* data, int size)
|
|||
int64_t dts = timestamp * 90;
|
||||
|
||||
// write audio to cache.
|
||||
if ((ret = cache->cache_audio(codec, dts, sample)) != ERROR_SUCCESS) {
|
||||
if ((ret = cache->cache_audio(format->audio, dts)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -3172,32 +3172,31 @@ int SrsTsEncoder::write_video(int64_t timestamp, char* data, int size)
|
|||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
sample->clear();
|
||||
if ((ret = codec->video_avc_demux(data, size, sample)) != ERROR_SUCCESS) {
|
||||
srs_error("http: ts codec demux video failed. ret=%d", ret);
|
||||
if ((ret = format->on_video(timestamp, data, size)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ignore info frame,
|
||||
// @see https://github.com/ossrs/srs/issues/288#issuecomment-69863909
|
||||
if (sample->frame_type == SrsCodecVideoAVCFrameVideoInfoFrame) {
|
||||
srs_assert(format->video && format->vcodec);
|
||||
if (format->video->frame_type == SrsCodecVideoAVCFrameVideoInfoFrame) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (codec->video_codec_id != SrsCodecVideoAVC) {
|
||||
if (format->vcodec->id != SrsCodecVideoAVC) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ignore sequence header
|
||||
if (sample->frame_type == SrsCodecVideoAVCFrameKeyFrame
|
||||
&& sample->avc_packet_type == SrsCodecVideoAVCTypeSequenceHeader) {
|
||||
if (format->video->frame_type == SrsCodecVideoAVCFrameKeyFrame
|
||||
&& format->video->avc_packet_type == SrsCodecVideoAVCTypeSequenceHeader) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
int64_t dts = timestamp * 90;
|
||||
|
||||
// write video to cache.
|
||||
if ((ret = cache->cache_video(codec, dts, sample)) != ERROR_SUCCESS) {
|
||||
if ((ret = cache->cache_video(format->video, dts)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -42,8 +42,7 @@ class SrsTsCache;
|
|||
class SrsTSMuxer;
|
||||
class SrsFileWriter;
|
||||
class SrsFileReader;
|
||||
class SrsAvcAacCodec;
|
||||
class SrsCodecSample;
|
||||
class SrsFormat;
|
||||
class SrsSimpleStream;
|
||||
class SrsTsAdaptationField;
|
||||
class SrsTsPayload;
|
||||
|
@ -1560,7 +1559,7 @@ protected:
|
|||
* write data from frame(header info) and buffer(data) to ts file.
|
||||
* it's a simple object wrapper for utility from nginx-rtmp: SrsMpegtsWriter
|
||||
*/
|
||||
class SrsTSMuxer
|
||||
class SrsTsMuxer
|
||||
{
|
||||
private:
|
||||
SrsCodecVideo vcodec;
|
||||
|
@ -1570,8 +1569,8 @@ private:
|
|||
SrsFileWriter* writer;
|
||||
std::string path;
|
||||
public:
|
||||
SrsTSMuxer(SrsFileWriter* w, SrsTsContext* c, SrsCodecAudio ac, SrsCodecVideo vc);
|
||||
virtual ~SrsTSMuxer();
|
||||
SrsTsMuxer(SrsFileWriter* w, SrsTsContext* c, SrsCodecAudio ac, SrsCodecVideo vc);
|
||||
virtual ~SrsTsMuxer();
|
||||
public:
|
||||
/**
|
||||
* open the writer, donot write the PSI of ts.
|
||||
|
@ -1585,6 +1584,7 @@ public:
|
|||
* @remark for audio aac codec, for example, SRS1, it's ok to write PSI when open ts.
|
||||
* @see https://github.com/ossrs/srs/issues/301
|
||||
*/
|
||||
// TODO: FIXME: Remove it.
|
||||
virtual int update_acodec(SrsCodecAudio ac);
|
||||
/**
|
||||
* write an audio frame to ts,
|
||||
|
@ -1628,29 +1628,29 @@ public:
|
|||
/**
|
||||
* write audio to cache
|
||||
*/
|
||||
virtual int cache_audio(SrsAvcAacCodec* codec, int64_t dts, SrsCodecSample* sample);
|
||||
virtual int cache_audio(SrsAudioFrame* frame, int64_t dts);
|
||||
/**
|
||||
* write video to muxer.
|
||||
*/
|
||||
virtual int cache_video(SrsAvcAacCodec* codec, int64_t dts, SrsCodecSample* sample);
|
||||
virtual int cache_video(SrsVideoFrame* frame, int64_t dts);
|
||||
private:
|
||||
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);
|
||||
virtual int do_cache_mp3(SrsAudioFrame* frame);
|
||||
virtual int do_cache_aac(SrsAudioFrame* frame);
|
||||
virtual int do_cache_avc(SrsVideoFrame* frame);
|
||||
};
|
||||
|
||||
/**
|
||||
* encode data to ts file.
|
||||
*/
|
||||
// TODO: FIXME: Rename it.
|
||||
class SrsTsEncoder
|
||||
{
|
||||
private:
|
||||
SrsFileWriter* writer;
|
||||
private:
|
||||
SrsAvcAacCodec* codec;
|
||||
SrsCodecSample* sample;
|
||||
SrsFormat* format;
|
||||
SrsTsCache* cache;
|
||||
SrsTSMuxer* muxer;
|
||||
SrsTsMuxer* muxer;
|
||||
SrsTsContext* context;
|
||||
public:
|
||||
SrsTsEncoder();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue