mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
for bug #293, http ts stream, move the avc codec from app to kernel.
This commit is contained in:
parent
dc6299171f
commit
913f98b902
17 changed files with 309 additions and 134 deletions
571
trunk/src/kernel/srs_kernel_avc.cpp
Normal file
571
trunk/src/kernel/srs_kernel_avc.cpp
Normal file
|
@ -0,0 +1,571 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-2015 winlin
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <srs_kernel_avc.hpp>
|
||||
|
||||
#include <srs_kernel_error.hpp>
|
||||
#include <srs_kernel_log.hpp>
|
||||
#include <srs_kernel_stream.hpp>
|
||||
#include <srs_kernel_utility.hpp>
|
||||
|
||||
SrsCodecSampleUnit::SrsCodecSampleUnit()
|
||||
{
|
||||
size = 0;
|
||||
bytes = NULL;
|
||||
}
|
||||
|
||||
SrsCodecSampleUnit::~SrsCodecSampleUnit()
|
||||
{
|
||||
}
|
||||
|
||||
SrsCodecSample::SrsCodecSample()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
SrsCodecSample::~SrsCodecSample()
|
||||
{
|
||||
}
|
||||
|
||||
void SrsCodecSample::clear()
|
||||
{
|
||||
is_video = false;
|
||||
nb_sample_units = 0;
|
||||
|
||||
cts = 0;
|
||||
frame_type = SrsCodecVideoAVCFrameReserved;
|
||||
avc_packet_type = SrsCodecVideoAVCTypeReserved;
|
||||
|
||||
sound_rate = SrsCodecAudioSampleRateReserved;
|
||||
sound_size = SrsCodecAudioSampleSizeReserved;
|
||||
sound_type = SrsCodecAudioSoundTypeReserved;
|
||||
aac_packet_type = SrsCodecAudioTypeReserved;
|
||||
}
|
||||
|
||||
int SrsCodecSample::add_sample_unit(char* bytes, int size)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
if (nb_sample_units >= __SRS_SRS_MAX_CODEC_SAMPLE) {
|
||||
ret = ERROR_HLS_DECODE_ERROR;
|
||||
srs_error("hls decode samples error, "
|
||||
"exceed the max count: %d, ret=%d", __SRS_SRS_MAX_CODEC_SAMPLE, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
SrsCodecSampleUnit* sample_unit = &sample_units[nb_sample_units++];
|
||||
sample_unit->bytes = bytes;
|
||||
sample_unit->size = size;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
SrsAvcAacCodec::SrsAvcAacCodec()
|
||||
{
|
||||
width = 0;
|
||||
height = 0;
|
||||
duration = 0;
|
||||
NAL_unit_length = 0;
|
||||
frame_rate = 0;
|
||||
video_data_rate = 0;
|
||||
video_codec_id = 0;
|
||||
audio_data_rate = 0;
|
||||
audio_codec_id = 0;
|
||||
avc_profile = 0;
|
||||
avc_level = 0;
|
||||
aac_profile = 0;
|
||||
aac_sample_rate = __SRS_AAC_SAMPLE_RATE_UNSET; // sample rate ignored
|
||||
aac_channels = 0;
|
||||
avc_extra_size = 0;
|
||||
avc_extra_data = NULL;
|
||||
aac_extra_size = 0;
|
||||
aac_extra_data = NULL;
|
||||
sequenceParameterSetLength = 0;
|
||||
sequenceParameterSetNALUnit = NULL;
|
||||
pictureParameterSetLength = 0;
|
||||
pictureParameterSetNALUnit = NULL;
|
||||
|
||||
stream = new SrsStream();
|
||||
}
|
||||
|
||||
SrsAvcAacCodec::~SrsAvcAacCodec()
|
||||
{
|
||||
srs_freep(avc_extra_data);
|
||||
srs_freep(aac_extra_data);
|
||||
|
||||
srs_freep(stream);
|
||||
srs_freep(sequenceParameterSetNALUnit);
|
||||
srs_freep(pictureParameterSetNALUnit);
|
||||
}
|
||||
|
||||
int SrsAvcAacCodec::audio_aac_demux(char* data, int size, SrsCodecSample* sample)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
sample->is_video = false;
|
||||
|
||||
if (!data || size <= 0) {
|
||||
srs_trace("no audio present, hls ignore it.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((ret = stream->initialize(data, size)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// audio decode
|
||||
if (!stream->require(1)) {
|
||||
ret = ERROR_HLS_DECODE_ERROR;
|
||||
srs_error("hls decode audio sound_format failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// @see: E.4.2 Audio Tags, video_file_format_spec_v10_1.pdf, page 76
|
||||
int8_t sound_format = stream->read_1bytes();
|
||||
|
||||
int8_t sound_type = sound_format & 0x01;
|
||||
int8_t sound_size = (sound_format >> 1) & 0x01;
|
||||
int8_t sound_rate = (sound_format >> 2) & 0x03;
|
||||
sound_format = (sound_format >> 4) & 0x0f;
|
||||
|
||||
audio_codec_id = sound_format;
|
||||
sample->sound_type = (SrsCodecAudioSoundType)sound_type;
|
||||
sample->sound_rate = (SrsCodecAudioSampleRate)sound_rate;
|
||||
sample->sound_size = (SrsCodecAudioSampleSize)sound_size;
|
||||
|
||||
// only support aac
|
||||
if (audio_codec_id != SrsCodecAudioAAC) {
|
||||
ret = ERROR_HLS_DECODE_ERROR;
|
||||
srs_error("hls only support audio aac codec. actual=%d, ret=%d", audio_codec_id, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!stream->require(1)) {
|
||||
ret = ERROR_HLS_DECODE_ERROR;
|
||||
srs_error("hls decode audio aac_packet_type failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int8_t aac_packet_type = stream->read_1bytes();
|
||||
sample->aac_packet_type = (SrsCodecAudioType)aac_packet_type;
|
||||
|
||||
if (aac_packet_type == SrsCodecAudioTypeSequenceHeader) {
|
||||
// AudioSpecificConfig
|
||||
// 1.6.2.1 AudioSpecificConfig, in aac-mp4a-format-ISO_IEC_14496-3+2001.pdf, page 33.
|
||||
aac_extra_size = stream->size() - stream->pos();
|
||||
if (aac_extra_size > 0) {
|
||||
srs_freep(aac_extra_data);
|
||||
aac_extra_data = new char[aac_extra_size];
|
||||
memcpy(aac_extra_data, stream->data() + stream->pos(), aac_extra_size);
|
||||
}
|
||||
|
||||
// only need to decode the first 2bytes:
|
||||
// audioObjectType, aac_profile, 5bits.
|
||||
// samplingFrequencyIndex, aac_sample_rate, 4bits.
|
||||
// channelConfiguration, aac_channels, 4bits
|
||||
if (!stream->require(2)) {
|
||||
ret = ERROR_HLS_DECODE_ERROR;
|
||||
srs_error("hls decode audio aac sequence header failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
aac_profile = stream->read_1bytes();
|
||||
aac_sample_rate = stream->read_1bytes();
|
||||
|
||||
aac_channels = (aac_sample_rate >> 3) & 0x0f;
|
||||
aac_sample_rate = ((aac_profile << 1) & 0x0e) | ((aac_sample_rate >> 7) & 0x01);
|
||||
aac_profile = (aac_profile >> 3) & 0x1f;
|
||||
|
||||
if (aac_profile == 0 || aac_profile == 0x1f) {
|
||||
ret = ERROR_HLS_DECODE_ERROR;
|
||||
srs_error("hls decode audio aac sequence header failed, "
|
||||
"adts object=%d invalid. ret=%d", aac_profile, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// TODO: FIXME: to support aac he/he-v2, see: ngx_rtmp_codec_parse_aac_header
|
||||
// @see: https://github.com/winlinvip/nginx-rtmp-module/commit/3a5f9eea78fc8d11e8be922aea9ac349b9dcbfc2
|
||||
//
|
||||
// donot force to LC, @see: https://github.com/winlinvip/simple-rtmp-server/issues/81
|
||||
// the source will print the sequence header info.
|
||||
//if (aac_profile > 3) {
|
||||
// Mark all extended profiles as LC
|
||||
// to make Android as happy as possible.
|
||||
// @see: ngx_rtmp_hls_parse_aac_header
|
||||
//aac_profile = 1;
|
||||
//}
|
||||
} else if (aac_packet_type == SrsCodecAudioTypeRawData) {
|
||||
// ensure the sequence header demuxed
|
||||
if (aac_extra_size <= 0 || !aac_extra_data) {
|
||||
ret = ERROR_HLS_DECODE_ERROR;
|
||||
srs_error("hls decode audio aac failed, sequence header not found. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Raw AAC frame data in UI8 []
|
||||
// 6.3 Raw Data, aac-iso-13818-7.pdf, page 28
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
// ignored.
|
||||
}
|
||||
|
||||
// reset the sample rate by sequence header
|
||||
if (aac_sample_rate != __SRS_AAC_SAMPLE_RATE_UNSET) {
|
||||
static int aac_sample_rates[] = {
|
||||
96000, 88200, 64000, 48000,
|
||||
44100, 32000, 24000, 22050,
|
||||
16000, 12000, 11025, 8000,
|
||||
7350, 0, 0, 0
|
||||
};
|
||||
switch (aac_sample_rates[aac_sample_rate]) {
|
||||
case 11025:
|
||||
sample->sound_rate = SrsCodecAudioSampleRate11025;
|
||||
break;
|
||||
case 22050:
|
||||
sample->sound_rate = SrsCodecAudioSampleRate22050;
|
||||
break;
|
||||
case 44100:
|
||||
sample->sound_rate = SrsCodecAudioSampleRate44100;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
srs_info("audio decoded, type=%d, codec=%d, asize=%d, rate=%d, format=%d, size=%d",
|
||||
sound_type, audio_codec_id, sound_size, sound_rate, sound_format, size);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsAvcAacCodec::video_avc_demux(char* data, int size, SrsCodecSample* sample)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
sample->is_video = true;
|
||||
|
||||
if (!data || size <= 0) {
|
||||
srs_trace("no video present, hls ignore it.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((ret = stream->initialize(data, size)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// video decode
|
||||
if (!stream->require(1)) {
|
||||
ret = ERROR_HLS_DECODE_ERROR;
|
||||
srs_error("hls decode video frame_type failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// @see: E.4.3 Video Tags, video_file_format_spec_v10_1.pdf, page 78
|
||||
int8_t frame_type = stream->read_1bytes();
|
||||
int8_t codec_id = frame_type & 0x0f;
|
||||
frame_type = (frame_type >> 4) & 0x0f;
|
||||
|
||||
sample->frame_type = (SrsCodecVideoAVCFrame)frame_type;
|
||||
|
||||
// ignore info frame without error,
|
||||
// @see https://github.com/winlinvip/simple-rtmp-server/issues/288#issuecomment-69863909
|
||||
if (sample->frame_type == SrsCodecVideoAVCFrameVideoInfoFrame) {
|
||||
srs_warn("hls igone the info frame, ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// only support h.264/avc
|
||||
if (codec_id != SrsCodecVideoAVC) {
|
||||
ret = ERROR_HLS_DECODE_ERROR;
|
||||
srs_error("hls only support video h.264/avc codec. actual=%d, ret=%d", codec_id, ret);
|
||||
return ret;
|
||||
}
|
||||
video_codec_id = codec_id;
|
||||
|
||||
if (!stream->require(4)) {
|
||||
ret = ERROR_HLS_DECODE_ERROR;
|
||||
srs_error("hls decode video avc_packet_type failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
int8_t avc_packet_type = stream->read_1bytes();
|
||||
int32_t composition_time = stream->read_3bytes();
|
||||
|
||||
// pts = dts + cts.
|
||||
sample->cts = composition_time;
|
||||
sample->avc_packet_type = (SrsCodecVideoAVCType)avc_packet_type;
|
||||
|
||||
if (avc_packet_type == SrsCodecVideoAVCTypeSequenceHeader) {
|
||||
if ((ret = avc_demux_sps_pps(stream)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
} else if (avc_packet_type == SrsCodecVideoAVCTypeNALU){
|
||||
// ensure the sequence header demuxed
|
||||
if (avc_extra_size <= 0 || !avc_extra_data) {
|
||||
ret = ERROR_HLS_DECODE_ERROR;
|
||||
srs_error("hls decode video avc failed, sequence header not found. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// One or more NALUs (Full frames are required)
|
||||
// try "AnnexB" from H.264-AVC-ISO_IEC_14496-10.pdf, page 211.
|
||||
if ((ret = avc_demux_annexb_format(stream, sample)) != ERROR_SUCCESS) {
|
||||
// stop try when system error.
|
||||
if (ret != ERROR_HLS_AVC_TRY_OTHERS) {
|
||||
srs_error("avc demux for annexb failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// try "ISO Base Media File Format" from H.264-AVC-ISO_IEC_14496-15.pdf, page 20
|
||||
if ((ret = avc_demux_ibmf_format(stream, sample)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// ignored.
|
||||
}
|
||||
|
||||
srs_info("video decoded, type=%d, codec=%d, avc=%d, time=%d, size=%d",
|
||||
frame_type, video_codec_id, avc_packet_type, composition_time, size);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsAvcAacCodec::avc_demux_sps_pps(SrsStream* stream)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
// AVCDecoderConfigurationRecord
|
||||
// 5.2.4.1.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16
|
||||
avc_extra_size = stream->size() - stream->pos();
|
||||
if (avc_extra_size > 0) {
|
||||
srs_freep(avc_extra_data);
|
||||
avc_extra_data = new char[avc_extra_size];
|
||||
memcpy(avc_extra_data, stream->data() + stream->pos(), avc_extra_size);
|
||||
}
|
||||
|
||||
if (!stream->require(6)) {
|
||||
ret = ERROR_HLS_DECODE_ERROR;
|
||||
srs_error("hls decode video avc sequenc header failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
//int8_t configurationVersion = stream->read_1bytes();
|
||||
stream->read_1bytes();
|
||||
//int8_t AVCProfileIndication = stream->read_1bytes();
|
||||
avc_profile = stream->read_1bytes();
|
||||
//int8_t profile_compatibility = stream->read_1bytes();
|
||||
stream->read_1bytes();
|
||||
//int8_t AVCLevelIndication = stream->read_1bytes();
|
||||
avc_level = stream->read_1bytes();
|
||||
|
||||
// parse the NALU size.
|
||||
int8_t lengthSizeMinusOne = stream->read_1bytes();
|
||||
lengthSizeMinusOne &= 0x03;
|
||||
NAL_unit_length = lengthSizeMinusOne;
|
||||
|
||||
// 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16
|
||||
// 5.2.4.1 AVC decoder configuration record
|
||||
// 5.2.4.1.2 Semantics
|
||||
// The value of this field shall be one of 0, 1, or 3 corresponding to a
|
||||
// length encoded with 1, 2, or 4 bytes, respectively.
|
||||
if (NAL_unit_length == 2) {
|
||||
ret = ERROR_HLS_DECODE_ERROR;
|
||||
srs_error("sps lengthSizeMinusOne should never be 2. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 1 sps
|
||||
if (!stream->require(1)) {
|
||||
ret = ERROR_HLS_DECODE_ERROR;
|
||||
srs_error("hls decode video avc sequenc header sps failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
int8_t numOfSequenceParameterSets = stream->read_1bytes();
|
||||
numOfSequenceParameterSets &= 0x1f;
|
||||
if (numOfSequenceParameterSets != 1) {
|
||||
ret = ERROR_HLS_DECODE_ERROR;
|
||||
srs_error("hls decode video avc sequenc header sps failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
if (!stream->require(2)) {
|
||||
ret = ERROR_HLS_DECODE_ERROR;
|
||||
srs_error("hls decode video avc sequenc header sps size failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
sequenceParameterSetLength = stream->read_2bytes();
|
||||
if (!stream->require(sequenceParameterSetLength)) {
|
||||
ret = ERROR_HLS_DECODE_ERROR;
|
||||
srs_error("hls decode video avc sequenc header sps data failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
if (sequenceParameterSetLength > 0) {
|
||||
srs_freep(sequenceParameterSetNALUnit);
|
||||
sequenceParameterSetNALUnit = new char[sequenceParameterSetLength];
|
||||
memcpy(sequenceParameterSetNALUnit, stream->data() + stream->pos(), sequenceParameterSetLength);
|
||||
stream->skip(sequenceParameterSetLength);
|
||||
}
|
||||
// 1 pps
|
||||
if (!stream->require(1)) {
|
||||
ret = ERROR_HLS_DECODE_ERROR;
|
||||
srs_error("hls decode video avc sequenc header pps failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
int8_t numOfPictureParameterSets = stream->read_1bytes();
|
||||
numOfPictureParameterSets &= 0x1f;
|
||||
if (numOfPictureParameterSets != 1) {
|
||||
ret = ERROR_HLS_DECODE_ERROR;
|
||||
srs_error("hls decode video avc sequenc header pps failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
if (!stream->require(2)) {
|
||||
ret = ERROR_HLS_DECODE_ERROR;
|
||||
srs_error("hls decode video avc sequenc header pps size failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
pictureParameterSetLength = stream->read_2bytes();
|
||||
if (!stream->require(pictureParameterSetLength)) {
|
||||
ret = ERROR_HLS_DECODE_ERROR;
|
||||
srs_error("hls decode video avc sequenc header pps data failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
if (pictureParameterSetLength > 0) {
|
||||
srs_freep(pictureParameterSetNALUnit);
|
||||
pictureParameterSetNALUnit = new char[pictureParameterSetLength];
|
||||
memcpy(pictureParameterSetNALUnit, stream->data() + stream->pos(), pictureParameterSetLength);
|
||||
stream->skip(pictureParameterSetLength);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsAvcAacCodec::avc_demux_annexb_format(SrsStream* stream, SrsCodecSample* sample)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
// not annexb, try others
|
||||
if (!srs_avc_startswith_annexb(stream, NULL)) {
|
||||
return ERROR_HLS_AVC_TRY_OTHERS;
|
||||
}
|
||||
|
||||
// AnnexB
|
||||
// B.1.1 Byte stream NAL unit syntax,
|
||||
// H.264-AVC-ISO_IEC_14496-10.pdf, page 211.
|
||||
while (!stream->empty()) {
|
||||
// find start code
|
||||
int nb_start_code = 0;
|
||||
if (!srs_avc_startswith_annexb(stream, &nb_start_code)) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// skip the start code.
|
||||
if (nb_start_code > 0) {
|
||||
stream->skip(nb_start_code);
|
||||
}
|
||||
|
||||
// the NALU start bytes.
|
||||
char* p = stream->data() + stream->pos();
|
||||
|
||||
// get the last matched NALU
|
||||
while (!stream->empty()) {
|
||||
if (srs_avc_startswith_annexb(stream, NULL)) {
|
||||
break;
|
||||
}
|
||||
|
||||
stream->skip(1);
|
||||
}
|
||||
|
||||
char* pp = stream->data() + stream->pos();
|
||||
|
||||
// skip the empty.
|
||||
if (pp - p <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// got the NALU.
|
||||
if ((ret = sample->add_sample_unit(p, pp - p)) != ERROR_SUCCESS) {
|
||||
srs_error("annexb add video sample failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsAvcAacCodec::avc_demux_ibmf_format(SrsStream* stream, SrsCodecSample* sample)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
int PictureLength = stream->size() - stream->pos();
|
||||
|
||||
// 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16
|
||||
// 5.2.4.1 AVC decoder configuration record
|
||||
// 5.2.4.1.2 Semantics
|
||||
// The value of this field shall be one of 0, 1, or 3 corresponding to a
|
||||
// length encoded with 1, 2, or 4 bytes, respectively.
|
||||
srs_assert(NAL_unit_length != 2);
|
||||
|
||||
// 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 20
|
||||
for (int i = 0; i < PictureLength;) {
|
||||
// unsigned int((NAL_unit_length+1)*8) NALUnitLength;
|
||||
if (!stream->require(NAL_unit_length + 1)) {
|
||||
ret = ERROR_HLS_DECODE_ERROR;
|
||||
srs_error("hls decode video avc NALU size failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
int32_t NALUnitLength = 0;
|
||||
if (NAL_unit_length == 3) {
|
||||
NALUnitLength = stream->read_4bytes();
|
||||
} else if (NAL_unit_length == 1) {
|
||||
NALUnitLength = stream->read_2bytes();
|
||||
} else {
|
||||
NALUnitLength = stream->read_1bytes();
|
||||
}
|
||||
|
||||
// maybe stream is invalid format.
|
||||
// see: https://github.com/winlinvip/simple-rtmp-server/issues/183
|
||||
if (NALUnitLength < 0) {
|
||||
ret = ERROR_HLS_DECODE_ERROR;
|
||||
srs_error("maybe stream is AnnexB format. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// NALUnit
|
||||
if (!stream->require(NALUnitLength)) {
|
||||
ret = ERROR_HLS_DECODE_ERROR;
|
||||
srs_error("hls decode video avc NALU data failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
// 7.3.1 NAL unit syntax, H.264-AVC-ISO_IEC_14496-10.pdf, page 44.
|
||||
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;
|
||||
}
|
||||
stream->skip(NALUnitLength);
|
||||
|
||||
i += NAL_unit_length + 1 + NALUnitLength;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
276
trunk/src/kernel/srs_kernel_avc.hpp
Normal file
276
trunk/src/kernel/srs_kernel_avc.hpp
Normal file
|
@ -0,0 +1,276 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-2015 winlin
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef SRS_KERNEL_AVC_HPP
|
||||
#define SRS_KERNEL_AVC_HPP
|
||||
|
||||
/*
|
||||
#include <srs_kernel_avc.hpp>
|
||||
*/
|
||||
|
||||
#include <srs_core.hpp>
|
||||
|
||||
#include <srs_kernel_codec.hpp>
|
||||
|
||||
class SrsStream;
|
||||
class SrsAmf0Object;
|
||||
|
||||
#define __SRS_SRS_MAX_CODEC_SAMPLE 128
|
||||
#define __SRS_AAC_SAMPLE_RATE_UNSET 15
|
||||
|
||||
/**
|
||||
* the FLV/RTMP supported audio sample size.
|
||||
* Size of each audio sample. This parameter only pertains to
|
||||
* uncompressed formats. Compressed formats always decode
|
||||
* to 16 bits internally.
|
||||
* 0 = 8-bit samples
|
||||
* 1 = 16-bit samples
|
||||
*/
|
||||
enum SrsCodecAudioSampleSize
|
||||
{
|
||||
// set to the max value to reserved, for array map.
|
||||
SrsCodecAudioSampleSizeReserved = 2,
|
||||
|
||||
SrsCodecAudioSampleSize8bit = 0,
|
||||
SrsCodecAudioSampleSize16bit = 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* the FLV/RTMP supported audio sound type/channel.
|
||||
* Mono or stereo sound
|
||||
* 0 = Mono sound
|
||||
* 1 = Stereo sound
|
||||
*/
|
||||
enum SrsCodecAudioSoundType
|
||||
{
|
||||
// set to the max value to reserved, for array map.
|
||||
SrsCodecAudioSoundTypeReserved = 2,
|
||||
|
||||
SrsCodecAudioSoundTypeMono = 0,
|
||||
SrsCodecAudioSoundTypeStereo = 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* 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 SrsCodecSampleUnit
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* the sample bytes is directly ptr to packet bytes,
|
||||
* user should never use it when packet destroyed.
|
||||
*/
|
||||
int size;
|
||||
char* bytes;
|
||||
public:
|
||||
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
|
||||
{
|
||||
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_SRS_MAX_CODEC_SAMPLE];
|
||||
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;
|
||||
public:
|
||||
// video specified
|
||||
SrsCodecVideoAVCFrame frame_type;
|
||||
SrsCodecVideoAVCType avc_packet_type;
|
||||
public:
|
||||
// audio specified
|
||||
SrsCodecAudioSampleRate sound_rate;
|
||||
SrsCodecAudioSampleSize sound_size;
|
||||
SrsCodecAudioSoundType sound_type;
|
||||
SrsCodecAudioType aac_packet_type;
|
||||
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();
|
||||
/**
|
||||
* 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 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
|
||||
{
|
||||
private:
|
||||
SrsStream* 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, H.264-AVC-ISO_IEC_14496-10.pdf, page 45.
|
||||
u_int8_t avc_profile;
|
||||
// level_idc, H.264-AVC-ISO_IEC_14496-10.pdf, page 45.
|
||||
u_int8_t avc_level;
|
||||
// lengthSizeMinusOne, H.264-AVC-ISO_IEC_14496-15.pdf, page 16
|
||||
int8_t NAL_unit_length;
|
||||
u_int16_t sequenceParameterSetLength;
|
||||
char* sequenceParameterSetNALUnit;
|
||||
u_int16_t pictureParameterSetLength;
|
||||
char* pictureParameterSetNALUnit;
|
||||
public:
|
||||
/**
|
||||
* audio specified
|
||||
* audioObjectType, in 1.6.2.1 AudioSpecificConfig, page 33,
|
||||
* 1.5.1.1 Audio object type definition, page 23,
|
||||
* in aac-mp4a-format-ISO_IEC_14496-3+2001.pdf.
|
||||
*/
|
||||
u_int8_t aac_profile;
|
||||
/**
|
||||
* samplingFrequencyIndex
|
||||
*/
|
||||
u_int8_t aac_sample_rate;
|
||||
/**
|
||||
* channelConfiguration
|
||||
*/
|
||||
u_int8_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;
|
||||
public:
|
||||
SrsAvcAacCodec();
|
||||
virtual ~SrsAvcAacCodec();
|
||||
// the following function used for hls to build the sample and codec.
|
||||
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);
|
||||
/**
|
||||
* 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);
|
||||
private:
|
||||
/**
|
||||
* when avc packet type is SrsCodecVideoAVCTypeSequenceHeader,
|
||||
* decode the sps and pps.
|
||||
*/
|
||||
virtual int avc_demux_sps_pps(SrsStream* stream);
|
||||
/**
|
||||
* demux the avc NALU in "AnnexB"
|
||||
* from H.264-AVC-ISO_IEC_14496-10.pdf, page 211.
|
||||
*/
|
||||
virtual int avc_demux_annexb_format(SrsStream* stream, SrsCodecSample* sample);
|
||||
/**
|
||||
* demux the avc NALU in "ISO Base Media File Format"
|
||||
* from H.264-AVC-ISO_IEC_14496-15.pdf, page 20
|
||||
*/
|
||||
virtual int avc_demux_ibmf_format(SrsStream* stream, SrsCodecSample* sample);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
80
trunk/src/kernel/srs_kernel_ts.cpp
Normal file
80
trunk/src/kernel/srs_kernel_ts.cpp
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-2015 winlin
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <srs_kernel_ts.hpp>
|
||||
|
||||
// for srs-librtmp, @see https://github.com/winlinvip/simple-rtmp-server/issues/213
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sstream>
|
||||
using namespace std;
|
||||
|
||||
#include <srs_kernel_log.hpp>
|
||||
#include <srs_kernel_error.hpp>
|
||||
#include <srs_kernel_stream.hpp>
|
||||
#include <srs_kernel_file.hpp>
|
||||
|
||||
SrsTsEncoder::SrsTsEncoder()
|
||||
{
|
||||
_fs = NULL;
|
||||
tag_stream = new SrsStream();
|
||||
}
|
||||
|
||||
SrsTsEncoder::~SrsTsEncoder()
|
||||
{
|
||||
srs_freep(tag_stream);
|
||||
}
|
||||
|
||||
int SrsTsEncoder::initialize(SrsFileWriter* fs)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
srs_assert(fs);
|
||||
|
||||
if (!fs->is_open()) {
|
||||
ret = ERROR_KERNEL_FLV_STREAM_CLOSED;
|
||||
srs_warn("stream is not open for encoder. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
_fs = fs;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsTsEncoder::write_audio(int64_t timestamp, char* data, int size)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsTsEncoder::write_video(int64_t timestamp, char* data, int size)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
65
trunk/src/kernel/srs_kernel_ts.hpp
Normal file
65
trunk/src/kernel/srs_kernel_ts.hpp
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-2015 winlin
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef SRS_KERNEL_TS_HPP
|
||||
#define SRS_KERNEL_TS_HPP
|
||||
|
||||
/*
|
||||
#include <srs_kernel_ts.hpp>
|
||||
*/
|
||||
#include <srs_core.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
class SrsStream;
|
||||
class SrsFileWriter;
|
||||
class SrsFileReader;
|
||||
|
||||
/**
|
||||
* encode data to ts file.
|
||||
*/
|
||||
class SrsTsEncoder
|
||||
{
|
||||
private:
|
||||
SrsFileWriter* _fs;
|
||||
private:
|
||||
SrsStream* tag_stream;
|
||||
public:
|
||||
SrsTsEncoder();
|
||||
virtual ~SrsTsEncoder();
|
||||
public:
|
||||
/**
|
||||
* initialize the underlayer file stream.
|
||||
*/
|
||||
virtual int initialize(SrsFileWriter* fs);
|
||||
public:
|
||||
/**
|
||||
* write audio/video packet.
|
||||
* @remark assert data is not NULL.
|
||||
*/
|
||||
virtual int write_audio(int64_t timestamp, char* data, int size);
|
||||
virtual int write_video(int64_t timestamp, char* data, int size);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -39,6 +39,7 @@ using namespace std;
|
|||
|
||||
#include <srs_kernel_log.hpp>
|
||||
#include <srs_kernel_error.hpp>
|
||||
#include <srs_kernel_stream.hpp>
|
||||
|
||||
// this value must:
|
||||
// equals to (SRS_SYS_CYCLE_INTERVAL*SRS_SYS_TIME_RESOLUTION_MS_TIMES)*1000
|
||||
|
@ -278,3 +279,50 @@ int srs_create_dir_recursively(string dir)
|
|||
return ret;
|
||||
}
|
||||
|
||||
bool srs_avc_startswith_annexb(SrsStream* stream, int* pnb_start_code)
|
||||
{
|
||||
char* bytes = stream->data() + stream->pos();
|
||||
char* p = bytes;
|
||||
|
||||
for (;;) {
|
||||
if (!stream->require(p - bytes + 3)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// not match
|
||||
if (p[0] != (char)0x00 || p[1] != (char)0x00) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// match N[00] 00 00 01, where N>=0
|
||||
if (p[2] == (char)0x01) {
|
||||
if (pnb_start_code) {
|
||||
*pnb_start_code = (int)(p - bytes) + 3;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
p++;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool srs_aac_startswith_adts(SrsStream* stream)
|
||||
{
|
||||
char* bytes = stream->data() + stream->pos();
|
||||
char* p = bytes;
|
||||
|
||||
if (!stream->require(p - bytes + 2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// matched 12bits 0xFFF,
|
||||
// @remark, we must cast the 0xff to char to compare.
|
||||
if (p[0] != (char)0xff || (char)(p[1] & 0xf0) != (char)0xf0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
|
||||
#include <string>
|
||||
|
||||
class SrsStream;
|
||||
|
||||
// compare
|
||||
#define srs_min(a, b) (((a) < (b))? (a) : (b))
|
||||
#define srs_max(a, b) (((a) < (b))? (b) : (a))
|
||||
|
@ -62,5 +64,21 @@ extern bool srs_string_ends_with(std::string str, std::string flag);
|
|||
// create dir recursively
|
||||
extern int srs_create_dir_recursively(std::string dir);
|
||||
|
||||
/**
|
||||
* whether stream starts with the avc NALU in "AnnexB"
|
||||
* from H.264-AVC-ISO_IEC_14496-10.pdf, page 211.
|
||||
* start code must be "N[00] 00 00 01" where N>=0
|
||||
* @param pnb_start_code output the size of start code, must >=3.
|
||||
* NULL to ignore.
|
||||
*/
|
||||
extern bool srs_avc_startswith_annexb(SrsStream* stream, int* pnb_start_code = NULL);
|
||||
|
||||
/**
|
||||
* whether stream starts with the aac ADTS
|
||||
* from aac-mp4a-format-ISO_IEC_14496-3+2001.pdf, page 75, 1.A.2.2 ADTS.
|
||||
* start code must be '1111 1111 1111'B, that is 0xFFF
|
||||
*/
|
||||
extern bool srs_aac_startswith_adts(SrsStream* stream);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue