mirror of
https://github.com/ossrs/srs.git
synced 2025-02-12 19:31:53 +00:00
refine codec, extract avc aac codec to app.
This commit is contained in:
parent
3dbe8ba9de
commit
6286759eaa
11 changed files with 715 additions and 616 deletions
2
trunk/configure
vendored
2
trunk/configure
vendored
|
@ -469,7 +469,7 @@ MODULE_FILES=("srs_app_server" "srs_app_conn" "srs_app_rtmp_conn" "srs_app_socke
|
|||
"srs_app_thread" "srs_app_bandwidth" "srs_app_st" "srs_app_log" "srs_app_config"
|
||||
"srs_app_pithy_print" "srs_app_reload" "srs_app_http_api" "srs_app_http_conn" "srs_app_http_hooks"
|
||||
"srs_app_json" "srs_app_ingest" "srs_app_ffmpeg" "srs_app_utility" "srs_app_dvr" "srs_app_edge"
|
||||
"srs_app_kbps" "srs_app_heartbeat" "srs_app_empty" "srs_app_http_client")
|
||||
"srs_app_kbps" "srs_app_heartbeat" "srs_app_empty" "srs_app_http_client" "srs_app_avc_aac")
|
||||
APP_INCS="src/app"; MODULE_DIR=${APP_INCS} . auto/modules.sh
|
||||
APP_OBJS="${MODULE_OBJS[@]}"
|
||||
#
|
||||
|
|
453
trunk/src/app/srs_app_avc_aac.cpp
Normal file
453
trunk/src/app/srs_app_avc_aac.cpp
Normal file
|
@ -0,0 +1,453 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-2014 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_app_avc_aac.hpp>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <srs_kernel_error.hpp>
|
||||
#include <srs_kernel_log.hpp>
|
||||
#include <srs_kernel_codec.hpp>
|
||||
#include <srs_kernel_stream.hpp>
|
||||
|
||||
SrsCodecBuffer::SrsCodecBuffer()
|
||||
{
|
||||
size = 0;
|
||||
bytes = NULL;
|
||||
}
|
||||
|
||||
void SrsCodecBuffer::append(void* data, int len)
|
||||
{
|
||||
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()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
SrsCodecSample::~SrsCodecSample()
|
||||
{
|
||||
}
|
||||
|
||||
void SrsCodecSample::clear()
|
||||
{
|
||||
is_video = false;
|
||||
nb_buffers = 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(char* bytes, int size)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
if (nb_buffers >= 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;
|
||||
|
||||
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 = 0;
|
||||
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(int8_t* 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((char*)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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
// reset the sample rate by sequence header
|
||||
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;
|
||||
};
|
||||
|
||||
// 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->left();
|
||||
if (aac_extra_size > 0) {
|
||||
srs_freep(aac_extra_data);
|
||||
aac_extra_data = new char[aac_extra_size];
|
||||
memcpy(aac_extra_data, stream->current(), 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;
|
||||
}
|
||||
|
||||
// aac_profile = audioObjectType - 1
|
||||
aac_profile--;
|
||||
|
||||
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(stream->current(), stream->left())) != ERROR_SUCCESS) {
|
||||
srs_error("hls add audio sample failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
// ignored.
|
||||
}
|
||||
|
||||
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(int8_t* 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((char*)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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
// 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) {
|
||||
// AVCDecoderConfigurationRecord
|
||||
// 5.2.4.1.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16
|
||||
avc_extra_size = stream->left();
|
||||
if (avc_extra_size > 0) {
|
||||
srs_freep(avc_extra_data);
|
||||
avc_extra_data = new char[avc_extra_size];
|
||||
memcpy(avc_extra_data, stream->current(), 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();
|
||||
//int8_t AVCProfileIndication = stream->read_1bytes();
|
||||
//int8_t profile_compatibility = stream->read_1bytes();
|
||||
//int8_t AVCLevelIndication = stream->read_1bytes();
|
||||
stream->skip(4);
|
||||
// parse the NALU size.
|
||||
int8_t lengthSizeMinusOne = stream->read_1bytes();
|
||||
lengthSizeMinusOne &= 0x03;
|
||||
NAL_unit_length = lengthSizeMinusOne;
|
||||
|
||||
// 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->current(), 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->current(), pictureParameterSetLength);
|
||||
stream->skip(pictureParameterSetLength);
|
||||
}
|
||||
} 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)
|
||||
// 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 20
|
||||
int PictureLength = stream->left();
|
||||
for (int i = 0; i < PictureLength;) {
|
||||
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 (NALUnitLength == 2) {
|
||||
NALUnitLength = stream->read_3bytes();
|
||||
} else if (NALUnitLength == 1) {
|
||||
NALUnitLength = stream->read_2bytes();
|
||||
} else {
|
||||
NALUnitLength = stream->read_1bytes();
|
||||
}
|
||||
// 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(stream->current(), NALUnitLength)) != ERROR_SUCCESS) {
|
||||
srs_error("hls add video sample failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
stream->skip(NALUnitLength);
|
||||
|
||||
i += NAL_unit_length + 1 + NALUnitLength;
|
||||
}
|
||||
} 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;
|
||||
}
|
198
trunk/src/app/srs_app_avc_aac.hpp
Normal file
198
trunk/src/app/srs_app_avc_aac.hpp
Normal file
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-2014 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_APP_AVC_AAC_HPP
|
||||
#define SRS_APP_AVC_AAC_HPP
|
||||
|
||||
/*
|
||||
#include <srs_app_avc_aac.hpp>
|
||||
*/
|
||||
|
||||
#include <srs_core.hpp>
|
||||
|
||||
#include <srs_kernel_codec.hpp>
|
||||
|
||||
#define SRS_MAX_CODEC_SAMPLE 128
|
||||
|
||||
// Sampling rate. The following values are defined:
|
||||
// 0 = 5.5 kHz = 5512 Hz
|
||||
// 1 = 11 kHz = 11025 Hz
|
||||
// 2 = 22 kHz = 22050 Hz
|
||||
// 3 = 44 kHz = 44100 Hz
|
||||
enum SrsCodecAudioSampleRate
|
||||
{
|
||||
SrsCodecAudioSampleRateReserved = -1,
|
||||
|
||||
SrsCodecAudioSampleRate5512 = 0,
|
||||
SrsCodecAudioSampleRate11025 = 1,
|
||||
SrsCodecAudioSampleRate22050 = 2,
|
||||
SrsCodecAudioSampleRate44100 = 3,
|
||||
};
|
||||
|
||||
// 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
|
||||
{
|
||||
SrsCodecAudioSampleSizeReserved = -1,
|
||||
|
||||
SrsCodecAudioSampleSize8bit = 0,
|
||||
SrsCodecAudioSampleSize16bit = 1,
|
||||
};
|
||||
|
||||
// Mono or stereo sound
|
||||
// 0 = Mono sound
|
||||
// 1 = Stereo sound
|
||||
enum SrsCodecAudioSoundType
|
||||
{
|
||||
SrsCodecAudioSoundTypeReserved = -1,
|
||||
|
||||
SrsCodecAudioSoundTypeMono = 0,
|
||||
SrsCodecAudioSoundTypeStereo = 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* buffer indicates the position and size.
|
||||
*/
|
||||
class SrsCodecBuffer
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @remark user must manage the bytes.
|
||||
*/
|
||||
int size;
|
||||
char* bytes;
|
||||
|
||||
SrsCodecBuffer();
|
||||
void append(void* data, int len);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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_buffers;
|
||||
SrsCodecBuffer buffers[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.
|
||||
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();
|
||||
void clear();
|
||||
int add_sample(char* bytes, int size);
|
||||
};
|
||||
|
||||
/**
|
||||
* the h264/avc and aac codec, for media stream.
|
||||
* to decode the stream of avc/aac for hls.
|
||||
*/
|
||||
class SrsAvcAacCodec
|
||||
{
|
||||
private:
|
||||
SrsStream* stream;
|
||||
public:
|
||||
/**
|
||||
* video specified
|
||||
*/
|
||||
// @see: SrsCodecVideo
|
||||
int video_codec_id;
|
||||
// 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;
|
||||
int width;
|
||||
int height;
|
||||
int video_data_rate; // in bps
|
||||
int frame_rate;
|
||||
int duration;
|
||||
// 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
|
||||
*/
|
||||
// @see: SrsCodecAudioType
|
||||
int audio_codec_id;
|
||||
int audio_data_rate; // in bps
|
||||
// 1.6.2.1 AudioSpecificConfig, in aac-mp4a-format-ISO_IEC_14496-3+2001.pdf, page 33.
|
||||
// audioObjectType, value defines in 7.1 Profiles, aac-iso-13818-7.pdf, page 40.
|
||||
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 codec info.
|
||||
public:
|
||||
virtual int audio_aac_demux(int8_t* data, int size, SrsCodecSample* sample);
|
||||
virtual int video_avc_demux(int8_t* data, int size, SrsCodecSample* sample);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -228,9 +228,9 @@ int SrsDvrPlan::on_video(SrsSharedPtrMessage* video)
|
|||
int size = (int)video->size;
|
||||
|
||||
#ifdef SRS_AUTO_HTTP_CALLBACK
|
||||
bool is_key_frame = SrsCodec::video_is_h264((int8_t*)payload, size)
|
||||
&& SrsCodec::video_is_keyframe((int8_t*)payload, size)
|
||||
&& !SrsCodec::video_is_sequence_header((int8_t*)payload, size);
|
||||
bool is_key_frame = SrsFlvCodec::video_is_h264((int8_t*)payload, size)
|
||||
&& SrsFlvCodec::video_is_keyframe((int8_t*)payload, size)
|
||||
&& !SrsFlvCodec::video_is_sequence_header((int8_t*)payload, size);
|
||||
if (is_key_frame) {
|
||||
segment->has_keyframe = true;
|
||||
if ((ret = on_video_keyframe()) != ERROR_SUCCESS) {
|
||||
|
|
|
@ -44,6 +44,7 @@ using namespace std;
|
|||
#include <srs_protocol_rtmp.hpp>
|
||||
#include <srs_app_pithy_print.hpp>
|
||||
#include <srs_kernel_utility.hpp>
|
||||
#include <srs_app_avc_aac.hpp>
|
||||
|
||||
// max PES packets size to flush the video.
|
||||
#define SRS_AUTO_HLS_AUDIO_CACHE_SIZE 1024 * 1024
|
||||
|
@ -1014,7 +1015,7 @@ int SrsHlsCache::on_sequence_header(SrsHlsMuxer* muxer)
|
|||
return muxer->on_sequence_header();
|
||||
}
|
||||
|
||||
int SrsHlsCache::write_audio(SrsCodec* codec, SrsHlsMuxer* muxer, int64_t pts, SrsCodecSample* sample)
|
||||
int SrsHlsCache::write_audio(SrsAvcAacCodec* codec, SrsHlsMuxer* muxer, int64_t pts, SrsCodecSample* sample)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
|
@ -1062,7 +1063,7 @@ int SrsHlsCache::write_audio(SrsCodec* codec, SrsHlsMuxer* muxer, int64_t pts, S
|
|||
}
|
||||
|
||||
int SrsHlsCache::write_video(
|
||||
SrsCodec* codec, SrsHlsMuxer* muxer, int64_t dts, SrsCodecSample* sample)
|
||||
SrsAvcAacCodec* codec, SrsHlsMuxer* muxer, int64_t dts, SrsCodecSample* sample)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
|
@ -1123,7 +1124,7 @@ int SrsHlsCache::reap_segment(string log_desc, SrsHlsMuxer* muxer, int64_t segme
|
|||
return ret;
|
||||
}
|
||||
|
||||
int SrsHlsCache::cache_audio(SrsCodec* codec, SrsCodecSample* sample)
|
||||
int SrsHlsCache::cache_audio(SrsAvcAacCodec* codec, SrsCodecSample* sample)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
|
@ -1190,7 +1191,7 @@ int SrsHlsCache::cache_audio(SrsCodec* codec, SrsCodecSample* sample)
|
|||
return ret;
|
||||
}
|
||||
|
||||
int SrsHlsCache::cache_video(SrsCodec* codec, SrsCodecSample* sample)
|
||||
int SrsHlsCache::cache_video(SrsAvcAacCodec* codec, SrsCodecSample* sample)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
|
@ -1262,7 +1263,7 @@ SrsHls::SrsHls(SrsSource* _source)
|
|||
hls_enabled = false;
|
||||
|
||||
source = _source;
|
||||
codec = new SrsCodec();
|
||||
codec = new SrsAvcAacCodec();
|
||||
sample = new SrsCodecSample();
|
||||
jitter = new SrsRtmpJitter();
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ class SrsMpegtsFrame;
|
|||
class SrsAmf0Object;
|
||||
class SrsRtmpJitter;
|
||||
class SrsTSMuxer;
|
||||
class SrsCodec;
|
||||
class SrsAvcAacCodec;
|
||||
class SrsRequest;
|
||||
class SrsPithyPrint;
|
||||
class SrsSource;
|
||||
|
@ -247,11 +247,11 @@ public:
|
|||
/**
|
||||
* write audio to cache, if need to flush, flush to muxer.
|
||||
*/
|
||||
virtual int write_audio(SrsCodec* codec, SrsHlsMuxer* muxer, int64_t pts, SrsCodecSample* sample);
|
||||
virtual int write_audio(SrsAvcAacCodec* codec, SrsHlsMuxer* muxer, int64_t pts, SrsCodecSample* sample);
|
||||
/**
|
||||
* write video to muxer.
|
||||
*/
|
||||
virtual int write_video(SrsCodec* codec, SrsHlsMuxer* muxer, int64_t dts, SrsCodecSample* sample);
|
||||
virtual int write_video(SrsAvcAacCodec* codec, SrsHlsMuxer* muxer, int64_t dts, SrsCodecSample* sample);
|
||||
private:
|
||||
/**
|
||||
* reopen the muxer for a new hls segment,
|
||||
|
@ -260,8 +260,8 @@ private:
|
|||
* so, user must reap_segment then flush_video to hls muxer.
|
||||
*/
|
||||
virtual int reap_segment(std::string log_desc, SrsHlsMuxer* muxer, int64_t segment_start_dts);
|
||||
virtual int cache_audio(SrsCodec* codec, SrsCodecSample* sample);
|
||||
virtual int cache_video(SrsCodec* codec, SrsCodecSample* sample);
|
||||
virtual int cache_audio(SrsAvcAacCodec* codec, SrsCodecSample* sample);
|
||||
virtual int cache_video(SrsAvcAacCodec* codec, SrsCodecSample* sample);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -277,7 +277,7 @@ private:
|
|||
private:
|
||||
bool hls_enabled;
|
||||
SrsSource* source;
|
||||
SrsCodec* codec;
|
||||
SrsAvcAacCodec* codec;
|
||||
SrsCodecSample* sample;
|
||||
SrsRtmpJitter* jitter;
|
||||
SrsPithyPrint* pithy_print;
|
||||
|
|
|
@ -201,7 +201,7 @@ void SrsMessageQueue::shrink()
|
|||
SrsSharedPtrMessage* msg = msgs[i];
|
||||
|
||||
if (msg->header.is_video()) {
|
||||
if (SrsCodec::video_is_keyframe(msg->payload, msg->size)) {
|
||||
if (SrsFlvCodec::video_is_keyframe(msg->payload, msg->size)) {
|
||||
// the max frame index to remove.
|
||||
iframe_index = i;
|
||||
|
||||
|
@ -363,7 +363,7 @@ int SrsGopCache::cache(SrsSharedPtrMessage* msg)
|
|||
}
|
||||
|
||||
// clear gop cache when got key frame
|
||||
if (msg->header.is_video() && SrsCodec::video_is_keyframe(msg->payload, msg->size)) {
|
||||
if (msg->header.is_video() && SrsFlvCodec::video_is_keyframe(msg->payload, msg->size)) {
|
||||
srs_info("clear gop cache when got keyframe. vcount=%d, count=%d",
|
||||
cached_video_count, (int)gop_cache.size());
|
||||
|
||||
|
@ -1012,7 +1012,7 @@ int SrsSource::on_audio(SrsMessage* audio)
|
|||
|
||||
// cache the sequence header if h264
|
||||
// donot cache the sequence header to gop_cache, return here.
|
||||
if (SrsCodec::audio_is_sequence_header(msg->payload, msg->size)) {
|
||||
if (SrsFlvCodec::audio_is_sequence_header(msg->payload, msg->size)) {
|
||||
srs_freep(cache_sh_audio);
|
||||
cache_sh_audio = msg->copy();
|
||||
srs_trace("got audio sh, size=%d", msg->header.payload_length);
|
||||
|
@ -1102,7 +1102,7 @@ int SrsSource::on_video(SrsMessage* video)
|
|||
|
||||
// cache the sequence header if h264
|
||||
// donot cache the sequence header to gop_cache, return here.
|
||||
if (SrsCodec::video_is_sequence_header(msg->payload, msg->size)) {
|
||||
if (SrsFlvCodec::video_is_sequence_header(msg->payload, msg->size)) {
|
||||
srs_freep(cache_sh_video);
|
||||
cache_sh_video = msg->copy();
|
||||
srs_trace("got video sh, size=%d", msg->header.payload_length);
|
||||
|
|
|
@ -31,429 +31,15 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
#include <srs_kernel_log.hpp>
|
||||
#include <srs_core_autofree.hpp>
|
||||
|
||||
SrsCodecBuffer::SrsCodecBuffer()
|
||||
{
|
||||
size = 0;
|
||||
bytes = NULL;
|
||||
}
|
||||
|
||||
void SrsCodecBuffer::append(void* data, int len)
|
||||
{
|
||||
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()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
SrsCodecSample::~SrsCodecSample()
|
||||
SrsFlvCodec::SrsFlvCodec()
|
||||
{
|
||||
}
|
||||
|
||||
void SrsCodecSample::clear()
|
||||
SrsFlvCodec::~SrsFlvCodec()
|
||||
{
|
||||
is_video = false;
|
||||
nb_buffers = 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(char* bytes, int size)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
if (nb_buffers >= 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;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
SrsCodec::SrsCodec()
|
||||
{
|
||||
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 = 0;
|
||||
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();
|
||||
}
|
||||
|
||||
SrsCodec::~SrsCodec()
|
||||
{
|
||||
srs_freep(avc_extra_data);
|
||||
srs_freep(aac_extra_data);
|
||||
|
||||
srs_freep(stream);
|
||||
srs_freep(sequenceParameterSetNALUnit);
|
||||
srs_freep(pictureParameterSetNALUnit);
|
||||
}
|
||||
|
||||
int SrsCodec::audio_aac_demux(int8_t* 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((char*)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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
// reset the sample rate by sequence header
|
||||
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;
|
||||
};
|
||||
|
||||
// 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->left();
|
||||
if (aac_extra_size > 0) {
|
||||
srs_freep(aac_extra_data);
|
||||
aac_extra_data = new char[aac_extra_size];
|
||||
memcpy(aac_extra_data, stream->current(), 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;
|
||||
}
|
||||
|
||||
// aac_profile = audioObjectType - 1
|
||||
aac_profile--;
|
||||
|
||||
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(stream->current(), stream->left())) != ERROR_SUCCESS) {
|
||||
srs_error("hls add audio sample failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
// ignored.
|
||||
}
|
||||
|
||||
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 SrsCodec::video_avc_demux(int8_t* 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((char*)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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
// 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) {
|
||||
// AVCDecoderConfigurationRecord
|
||||
// 5.2.4.1.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16
|
||||
avc_extra_size = stream->left();
|
||||
if (avc_extra_size > 0) {
|
||||
srs_freep(avc_extra_data);
|
||||
avc_extra_data = new char[avc_extra_size];
|
||||
memcpy(avc_extra_data, stream->current(), 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();
|
||||
//int8_t AVCProfileIndication = stream->read_1bytes();
|
||||
//int8_t profile_compatibility = stream->read_1bytes();
|
||||
//int8_t AVCLevelIndication = stream->read_1bytes();
|
||||
stream->skip(4);
|
||||
// parse the NALU size.
|
||||
int8_t lengthSizeMinusOne = stream->read_1bytes();
|
||||
lengthSizeMinusOne &= 0x03;
|
||||
NAL_unit_length = lengthSizeMinusOne;
|
||||
|
||||
// 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->current(), 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->current(), pictureParameterSetLength);
|
||||
stream->skip(pictureParameterSetLength);
|
||||
}
|
||||
} 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)
|
||||
// 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 20
|
||||
int PictureLength = stream->left();
|
||||
for (int i = 0; i < PictureLength;) {
|
||||
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 (NALUnitLength == 2) {
|
||||
NALUnitLength = stream->read_3bytes();
|
||||
} else if (NALUnitLength == 1) {
|
||||
NALUnitLength = stream->read_2bytes();
|
||||
} else {
|
||||
NALUnitLength = stream->read_1bytes();
|
||||
}
|
||||
// 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(stream->current(), NALUnitLength)) != ERROR_SUCCESS) {
|
||||
srs_error("hls add video sample failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
stream->skip(NALUnitLength);
|
||||
|
||||
i += NAL_unit_length + 1 + NALUnitLength;
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
|
||||
bool SrsCodec::video_is_keyframe(int8_t* data, int size)
|
||||
bool SrsFlvCodec::video_is_keyframe(int8_t* data, int size)
|
||||
{
|
||||
// 2bytes required.
|
||||
if (size < 1) {
|
||||
|
@ -466,7 +52,7 @@ bool SrsCodec::video_is_keyframe(int8_t* data, int size)
|
|||
return frame_type == SrsCodecVideoAVCFrameKeyFrame;
|
||||
}
|
||||
|
||||
bool SrsCodec::video_is_sequence_header(int8_t* data, int size)
|
||||
bool SrsFlvCodec::video_is_sequence_header(int8_t* data, int size)
|
||||
{
|
||||
// sequence header only for h264
|
||||
if (!video_is_h264(data, size)) {
|
||||
|
@ -487,7 +73,7 @@ bool SrsCodec::video_is_sequence_header(int8_t* data, int size)
|
|||
&& avc_packet_type == SrsCodecVideoAVCTypeSequenceHeader;
|
||||
}
|
||||
|
||||
bool SrsCodec::audio_is_sequence_header(int8_t* data, int size)
|
||||
bool SrsFlvCodec::audio_is_sequence_header(int8_t* data, int size)
|
||||
{
|
||||
// sequence header only for aac
|
||||
if (!audio_is_aac(data, size)) {
|
||||
|
@ -504,7 +90,7 @@ bool SrsCodec::audio_is_sequence_header(int8_t* data, int size)
|
|||
return aac_packet_type == SrsCodecAudioTypeSequenceHeader;
|
||||
}
|
||||
|
||||
bool SrsCodec::video_is_h264(int8_t* data, int size)
|
||||
bool SrsFlvCodec::video_is_h264(int8_t* data, int size)
|
||||
{
|
||||
// 1bytes required.
|
||||
if (size < 1) {
|
||||
|
@ -517,7 +103,7 @@ bool SrsCodec::video_is_h264(int8_t* data, int size)
|
|||
return codec_id == SrsCodecVideoAVC;
|
||||
}
|
||||
|
||||
bool SrsCodec::audio_is_aac(int8_t* data, int size)
|
||||
bool SrsFlvCodec::audio_is_aac(int8_t* data, int size)
|
||||
{
|
||||
// 1bytes required.
|
||||
if (size < 1) {
|
||||
|
|
|
@ -30,29 +30,17 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
|
||||
#include <srs_core.hpp>
|
||||
|
||||
#define SRS_MAX_CODEC_SAMPLE 128
|
||||
|
||||
class SrsStream;
|
||||
|
||||
// E.4.3.1 VIDEODATA
|
||||
// CodecID UB [4]
|
||||
// Codec Identifier. The following values are defined:
|
||||
// 2 = Sorenson H.263
|
||||
// 3 = Screen video
|
||||
// 4 = On2 VP6
|
||||
// 5 = On2 VP6 with alpha channel
|
||||
// 6 = Screen video version 2
|
||||
// 7 = AVC
|
||||
enum SrsCodecVideo
|
||||
// AACPacketType IF SoundFormat == 10 UI8
|
||||
// The following values are defined:
|
||||
// 0 = AAC sequence header
|
||||
// 1 = AAC raw
|
||||
enum SrsCodecAudioType
|
||||
{
|
||||
SrsCodecVideoReserved = 0,
|
||||
|
||||
SrsCodecVideoSorensonH263 = 2,
|
||||
SrsCodecVideoScreenVideo = 3,
|
||||
SrsCodecVideoOn2VP6 = 4,
|
||||
SrsCodecVideoOn2VP6WithAlphaChannel = 5,
|
||||
SrsCodecVideoScreenVideoVersion2 = 6,
|
||||
SrsCodecVideoAVC = 7,
|
||||
SrsCodecAudioTypeReserved = -1,
|
||||
SrsCodecAudioTypeSequenceHeader = 0,
|
||||
SrsCodecAudioTypeRawData = 1,
|
||||
};
|
||||
|
||||
// E.4.3.1 VIDEODATA
|
||||
|
@ -89,6 +77,27 @@ enum SrsCodecVideoAVCType
|
|||
SrsCodecVideoAVCTypeSequenceHeaderEOF = 2,
|
||||
};
|
||||
|
||||
// E.4.3.1 VIDEODATA
|
||||
// CodecID UB [4]
|
||||
// Codec Identifier. The following values are defined:
|
||||
// 2 = Sorenson H.263
|
||||
// 3 = Screen video
|
||||
// 4 = On2 VP6
|
||||
// 5 = On2 VP6 with alpha channel
|
||||
// 6 = Screen video version 2
|
||||
// 7 = AVC
|
||||
enum SrsCodecVideo
|
||||
{
|
||||
SrsCodecVideoReserved = 0,
|
||||
|
||||
SrsCodecVideoSorensonH263 = 2,
|
||||
SrsCodecVideoScreenVideo = 3,
|
||||
SrsCodecVideoOn2VP6 = 4,
|
||||
SrsCodecVideoOn2VP6WithAlphaChannel = 5,
|
||||
SrsCodecVideoScreenVideoVersion2 = 6,
|
||||
SrsCodecVideoAVC = 7,
|
||||
};
|
||||
|
||||
// SoundFormat UB [4]
|
||||
// Format of SoundData. The following values are defined:
|
||||
// 0 = Linear PCM, platform endian
|
||||
|
@ -126,165 +135,15 @@ enum SrsCodecAudio
|
|||
SrsCodecAudioReservedDeviceSpecificSound = 15,
|
||||
};
|
||||
|
||||
// AACPacketType IF SoundFormat == 10 UI8
|
||||
// The following values are defined:
|
||||
// 0 = AAC sequence header
|
||||
// 1 = AAC raw
|
||||
enum SrsCodecAudioType
|
||||
{
|
||||
SrsCodecAudioTypeReserved = -1,
|
||||
SrsCodecAudioTypeSequenceHeader = 0,
|
||||
SrsCodecAudioTypeRawData = 1,
|
||||
};
|
||||
|
||||
// Sampling rate. The following values are defined:
|
||||
// 0 = 5.5 kHz = 5512 Hz
|
||||
// 1 = 11 kHz = 11025 Hz
|
||||
// 2 = 22 kHz = 22050 Hz
|
||||
// 3 = 44 kHz = 44100 Hz
|
||||
enum SrsCodecAudioSampleRate
|
||||
{
|
||||
SrsCodecAudioSampleRateReserved = -1,
|
||||
|
||||
SrsCodecAudioSampleRate5512 = 0,
|
||||
SrsCodecAudioSampleRate11025 = 1,
|
||||
SrsCodecAudioSampleRate22050 = 2,
|
||||
SrsCodecAudioSampleRate44100 = 3,
|
||||
};
|
||||
|
||||
// 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
|
||||
{
|
||||
SrsCodecAudioSampleSizeReserved = -1,
|
||||
|
||||
SrsCodecAudioSampleSize8bit = 0,
|
||||
SrsCodecAudioSampleSize16bit = 1,
|
||||
};
|
||||
|
||||
// Mono or stereo sound
|
||||
// 0 = Mono sound
|
||||
// 1 = Stereo sound
|
||||
enum SrsCodecAudioSoundType
|
||||
{
|
||||
SrsCodecAudioSoundTypeReserved = -1,
|
||||
|
||||
SrsCodecAudioSoundTypeMono = 0,
|
||||
SrsCodecAudioSoundTypeStereo = 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* buffer indicates the position and size.
|
||||
*/
|
||||
class SrsCodecBuffer
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @remark user must manage the bytes.
|
||||
*/
|
||||
int size;
|
||||
char* bytes;
|
||||
|
||||
SrsCodecBuffer();
|
||||
void append(void* data, int len);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
class SrsCodecSample
|
||||
{
|
||||
public:
|
||||
int nb_buffers;
|
||||
SrsCodecBuffer buffers[SRS_MAX_CODEC_SAMPLE];
|
||||
public:
|
||||
bool is_video;
|
||||
// video specified
|
||||
SrsCodecVideoAVCFrame frame_type;
|
||||
SrsCodecVideoAVCType avc_packet_type;
|
||||
// CompositionTime, video_file_format_spec_v10_1.pdf, page 78.
|
||||
// cts = pts - dts, where dts = flvheader->timestamp.
|
||||
int32_t cts;
|
||||
// audio specified
|
||||
SrsCodecAudioSampleRate sound_rate;
|
||||
SrsCodecAudioSampleSize sound_size;
|
||||
SrsCodecAudioSoundType sound_type;
|
||||
SrsCodecAudioType aac_packet_type;
|
||||
public:
|
||||
SrsCodecSample();
|
||||
virtual ~SrsCodecSample();
|
||||
void clear();
|
||||
int add_sample(char* bytes, int size);
|
||||
};
|
||||
|
||||
/**
|
||||
* Annex E. The FLV File Format
|
||||
* @see SrsAvcAacCodec for the media stream codec.
|
||||
*/
|
||||
class SrsCodec
|
||||
class SrsFlvCodec
|
||||
{
|
||||
private:
|
||||
SrsStream* stream;
|
||||
public:
|
||||
/**
|
||||
* video specified
|
||||
*/
|
||||
// @see: SrsCodecVideo
|
||||
int video_codec_id;
|
||||
// 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;
|
||||
int width;
|
||||
int height;
|
||||
int video_data_rate; // in bps
|
||||
int frame_rate;
|
||||
int duration;
|
||||
// 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;
|
||||
/**
|
||||
* audio specified
|
||||
*/
|
||||
// @see: SrsCodecAudioType
|
||||
int audio_codec_id;
|
||||
int audio_data_rate; // in bps
|
||||
// 1.6.2.1 AudioSpecificConfig, in aac-mp4a-format-ISO_IEC_14496-3+2001.pdf, page 33.
|
||||
// audioObjectType, value defines in 7.1 Profiles, aac-iso-13818-7.pdf, page 40.
|
||||
u_int8_t aac_profile;
|
||||
// samplingFrequencyIndex
|
||||
u_int8_t aac_sample_rate;
|
||||
// channelConfiguration
|
||||
u_int8_t aac_channels;
|
||||
// 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:
|
||||
SrsCodec();
|
||||
virtual ~SrsCodec();
|
||||
// the following function used for hls to build the codec info.
|
||||
public:
|
||||
virtual int audio_aac_demux(int8_t* data, int size, SrsCodecSample* sample);
|
||||
virtual int video_avc_demux(int8_t* data, int size, SrsCodecSample* sample);
|
||||
SrsFlvCodec();
|
||||
virtual ~SrsFlvCodec();
|
||||
// the following function used to finger out the flv/rtmp packet detail.
|
||||
public:
|
||||
/**
|
||||
|
|
|
@ -540,12 +540,12 @@ flv_bool srs_flv_is_eof(int error_code)
|
|||
|
||||
flv_bool srs_flv_is_sequence_header(char* data, int32_t size)
|
||||
{
|
||||
return SrsCodec::video_is_sequence_header((int8_t*)data, (int)size);
|
||||
return SrsFlvCodec::video_is_sequence_header((int8_t*)data, (int)size);
|
||||
}
|
||||
|
||||
flv_bool srs_flv_is_keyframe(char* data, int32_t size)
|
||||
{
|
||||
return SrsCodec::video_is_keyframe((int8_t*)data, (int)size);
|
||||
return SrsFlvCodec::video_is_keyframe((int8_t*)data, (int)size);
|
||||
}
|
||||
|
||||
srs_amf0_t srs_amf0_parse(char* data, int size, int* nparsed)
|
||||
|
|
|
@ -43,6 +43,8 @@ file
|
|||
..\rtmp\srs_protocol_utility.hpp,
|
||||
..\rtmp\srs_protocol_utility.cpp,
|
||||
app readonly separator,
|
||||
..\app\srs_app_avc_aac.hpp,
|
||||
..\app\srs_app_avc_aac.cpp,
|
||||
..\app\srs_app_bandwidth.hpp,
|
||||
..\app\srs_app_bandwidth.cpp,
|
||||
..\app\srs_app_conn.hpp,
|
||||
|
|
Loading…
Reference in a new issue