mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
fix #212, support publish aac adts raw stream. 2.0.31.
This commit is contained in:
parent
3d97048c3a
commit
e492fa5353
15 changed files with 620 additions and 86 deletions
|
@ -451,6 +451,10 @@ Supported operating systems and hardware:
|
|||
1. Support compile [srs-librtmp on windows](https://github.com/winlinvip/srs.librtmp),
|
||||
[bug #213](https://github.com/winlinvip/simple-rtmp-server/issues/213).
|
||||
1. Support [7.5k+ clients](https://github.com/winlinvip/simple-rtmp-server/issues/217), 4Gbps per process.
|
||||
1. Support publish aac adts raw stream(
|
||||
[CN](https://github.com/winlinvip/simple-rtmp-server/wiki/v2_CN_SrsLibrtmp#publish-audio-raw-stream),
|
||||
[EN](https://github.com/winlinvip/simple-rtmp-server/wiki/v2_EN_SrsLibrtmp#publish-audio-raw-stream)
|
||||
) by srs-librtmp.
|
||||
1. [no-plan] Support <500ms latency, FRSC(Fast RTMP-compatible Stream Channel tech).
|
||||
1. [no-plan] Support RTMP 302 redirect [#92](https://github.com/winlinvip/simple-rtmp-server/issues/92).
|
||||
1. [no-plan] Support multiple processes, for both origin and edge
|
||||
|
@ -483,6 +487,7 @@ Supported operating systems and hardware:
|
|||
* 2013-10-17, Created.<br/>
|
||||
|
||||
## History
|
||||
* v2.0, 2014-11-24, fix [#212](https://github.com/winlinvip/simple-rtmp-server/issues/212), support publish aac adts raw stream. 2.0.31.
|
||||
* v2.0, 2014-11-22, fix [#217](https://github.com/winlinvip/simple-rtmp-server/issues/217), remove timeout recv, support 7.5k+ 250kbps clients. 2.0.30.
|
||||
* v2.0, 2014-11-21, srs-librtmp add rtmp prefix for rtmp/utils/human apis. 2.0.29.
|
||||
* v2.0, 2014-11-21, refine examples of srs-librtmp, add srs_print_rtmp_packet. 2.0.28.
|
||||
|
|
|
@ -7,7 +7,7 @@ else
|
|||
objs/srs_flv_injecter objs/srs_publish objs/srs_play \
|
||||
objs/srs_ingest_flv objs/srs_ingest_rtmp objs/srs_detect_rtmp \
|
||||
objs/srs_bandwidth_check objs/srs_h264_raw_publish \
|
||||
objs/srs_audio_raw_publish
|
||||
objs/srs_audio_raw_publish objs/srs_aac_raw_publish
|
||||
endif
|
||||
|
||||
.PHONY: default clean help ssl nossl
|
||||
|
@ -26,6 +26,7 @@ help:
|
|||
@echo " srs_publish publish program using srs-librtmp"
|
||||
@echo " srs_h264_raw_publish publish raw h.264 stream to SSR by srs-librtmp"
|
||||
@echo " srs_audio_raw_publish publish raw audio stream to SSR by srs-librtmp"
|
||||
@echo " srs_aac_raw_publish publish raw aac stream to SSR by srs-librtmp"
|
||||
@echo " srs_play play program using srs-librtmp"
|
||||
@echo " srs_ingest_flv ingest flv file and publish to RTMP server."
|
||||
@echo " srs_ingest_rtmp ingest RTMP and publish to RTMP server."
|
||||
|
@ -90,6 +91,9 @@ objs/srs_h264_raw_publish: srs_h264_raw_publish.c $(SRS_RESEARCH_DEPS) $(SRS_LIB
|
|||
objs/srs_audio_raw_publish: srs_audio_raw_publish.c $(SRS_RESEARCH_DEPS) $(SRS_LIBRTMP_I) $(SRS_LIBRTMP_L) $(SRS_LIBSSL_L)
|
||||
$(GCC) srs_audio_raw_publish.c $(SRS_LIBRTMP_L) $(SRS_LIBSSL_L) $(EXTRA_CXX_FLAG) -o objs/srs_audio_raw_publish
|
||||
|
||||
objs/srs_aac_raw_publish: srs_aac_raw_publish.c $(SRS_RESEARCH_DEPS) $(SRS_LIBRTMP_I) $(SRS_LIBRTMP_L) $(SRS_LIBSSL_L)
|
||||
$(GCC) srs_aac_raw_publish.c $(SRS_LIBRTMP_L) $(SRS_LIBSSL_L) $(EXTRA_CXX_FLAG) -o objs/srs_aac_raw_publish
|
||||
|
||||
objs/srs_play: srs_play.c $(SRS_RESEARCH_DEPS) $(SRS_LIBRTMP_I) $(SRS_LIBRTMP_L) $(SRS_LIBSSL_L)
|
||||
$(GCC) srs_play.c $(SRS_LIBRTMP_L) $(SRS_LIBSSL_L) $(EXTRA_CXX_FLAG) -o objs/srs_play
|
||||
|
||||
|
|
198
trunk/research/librtmp/srs_aac_raw_publish.c
Normal file
198
trunk/research/librtmp/srs_aac_raw_publish.c
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.
|
||||
*/
|
||||
/**
|
||||
gcc srs_aac_raw_publish.c ../../objs/lib/srs_librtmp.a -g -O0 -lstdc++ -o srs_aac_raw_publish
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// for open audio raw file.
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "../../objs/include/srs_librtmp.h"
|
||||
|
||||
// https://github.com/winlinvip/simple-rtmp-server/issues/212#issuecomment-63648892
|
||||
// allspace:
|
||||
// Take this file as an example: https://github.com/allspace/files/blob/master/srs.pcm
|
||||
// It's captured using SDK callback method. I have filtered out h264 video, so it's audio only now.
|
||||
// For every frame, it's a 8 bytes vendor specific header, following 160 bytes audio frame.
|
||||
// The header part can be ignored.
|
||||
int read_audio_frame(char* data, int size, char** pp, char** frame, int* frame_size)
|
||||
{
|
||||
char* p = *pp;
|
||||
|
||||
// @remark, for this demo, to publish aac raw file to SRS,
|
||||
// we search the adts frame from the buffer which cached the aac data.
|
||||
// please get aac adts raw data from device, it always a encoded frame.
|
||||
if (!srs_aac_is_adts(p, size - (p - data))) {
|
||||
srs_human_trace("aac adts raw data invalid.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// @see srs_audio_write_raw_frame
|
||||
// each frame prefixed aac adts header, '1111 1111 1111'B, that is 0xFFF.,
|
||||
// for instance, frame = FF F1 5C 80 13 A0 FC 00 D0 33 83 E8 5B
|
||||
*frame = p;
|
||||
// skip some data.
|
||||
// @remark, user donot need to do this.
|
||||
p += srs_aac_adts_frame_size(p, size - (p - data));
|
||||
|
||||
*pp = p;
|
||||
*frame_size = p - *frame;
|
||||
if (*frame_size <= 0) {
|
||||
srs_human_trace("aac adts raw data invalid.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
printf("publish raw audio as rtmp stream to server like FMLE/FFMPEG/Encoder\n");
|
||||
printf("SRS(simple-rtmp-server) client librtmp library.\n");
|
||||
printf("version: %d.%d.%d\n", srs_version_major(), srs_version_minor(), srs_version_revision());
|
||||
|
||||
if (argc <= 2) {
|
||||
printf("Usage: %s <audio_raw_file> <rtmp_publish_url>\n", argv[0]);
|
||||
printf(" audio_raw_file: the audio raw steam file.\n");
|
||||
printf(" rtmp_publish_url: the rtmp publish url.\n");
|
||||
printf("For example:\n");
|
||||
printf(" %s ./audio.raw.aac rtmp://127.0.0.1:1935/live/livestream\n", argv[0]);
|
||||
printf("Where the file: http://winlinvip.github.io/srs.release/3rdparty/audio.raw.aac\n");
|
||||
printf("See: https://github.com/winlinvip/simple-rtmp-server/issues/212\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
const char* raw_file = argv[1];
|
||||
const char* rtmp_url = argv[2];
|
||||
srs_human_trace("raw_file=%s, rtmp_url=%s", raw_file, rtmp_url);
|
||||
|
||||
// open file
|
||||
int raw_fd = open(raw_file, O_RDONLY);
|
||||
if (raw_fd < 0) {
|
||||
srs_human_trace("open audio raw file %s failed.", raw_fd);
|
||||
goto rtmp_destroy;
|
||||
}
|
||||
|
||||
off_t file_size = lseek(raw_fd, 0, SEEK_END);
|
||||
if (file_size <= 0) {
|
||||
srs_human_trace("audio raw file %s empty.", raw_file);
|
||||
goto rtmp_destroy;
|
||||
}
|
||||
srs_human_trace("read entirely audio raw file, size=%dKB", (int)(file_size / 1024));
|
||||
|
||||
char* audio_raw = (char*)malloc(file_size);
|
||||
if (!audio_raw) {
|
||||
srs_human_trace("alloc raw buffer failed for file %s.", raw_file);
|
||||
goto rtmp_destroy;
|
||||
}
|
||||
|
||||
lseek(raw_fd, 0, SEEK_SET);
|
||||
ssize_t nb_read = 0;
|
||||
if ((nb_read = read(raw_fd, audio_raw, file_size)) != file_size) {
|
||||
srs_human_trace("buffer %s failed, expect=%dKB, actual=%dKB.",
|
||||
raw_file, (int)(file_size / 1024), (int)(nb_read / 1024));
|
||||
goto rtmp_destroy;
|
||||
}
|
||||
|
||||
// connect rtmp context
|
||||
srs_rtmp_t rtmp = srs_rtmp_create(rtmp_url);
|
||||
|
||||
if (srs_rtmp_handshake(rtmp) != 0) {
|
||||
srs_human_trace("simple handshake failed.");
|
||||
goto rtmp_destroy;
|
||||
}
|
||||
srs_human_trace("simple handshake success");
|
||||
|
||||
if (srs_rtmp_connect_app(rtmp) != 0) {
|
||||
srs_human_trace("connect vhost/app failed.");
|
||||
goto rtmp_destroy;
|
||||
}
|
||||
srs_human_trace("connect vhost/app success");
|
||||
|
||||
if (srs_rtmp_publish_stream(rtmp) != 0) {
|
||||
srs_human_trace("publish stream failed.");
|
||||
goto rtmp_destroy;
|
||||
}
|
||||
srs_human_trace("publish stream success");
|
||||
|
||||
u_int32_t timestamp = 0;
|
||||
u_int32_t time_delta = 45;
|
||||
// @remark, to decode the file.
|
||||
char* p = audio_raw;
|
||||
for (;p < audio_raw + file_size;) {
|
||||
// @remark, read a frame from file buffer.
|
||||
char* data = NULL;
|
||||
int size = 0;
|
||||
if (read_audio_frame(audio_raw, file_size, &p, &data, &size) < 0) {
|
||||
srs_human_trace("read a frame from file buffer failed.");
|
||||
goto rtmp_destroy;
|
||||
}
|
||||
|
||||
// 0 = Linear PCM, platform endian
|
||||
// 1 = ADPCM
|
||||
// 2 = MP3
|
||||
// 7 = G.711 A-law logarithmic PCM
|
||||
// 8 = G.711 mu-law logarithmic PCM
|
||||
// 10 = AAC
|
||||
// 11 = Speex
|
||||
char sound_format = 10;
|
||||
// 2 = 22 kHz
|
||||
char sound_rate = 2;
|
||||
// 1 = 16-bit samples
|
||||
char sound_size = 1;
|
||||
// 1 = Stereo sound
|
||||
char sound_type = 1;
|
||||
|
||||
timestamp += time_delta;
|
||||
|
||||
int ret = 0;
|
||||
if ((ret = srs_audio_write_raw_frame(rtmp,
|
||||
sound_format, sound_rate, sound_size, sound_type,
|
||||
data, size, timestamp)) != 0
|
||||
) {
|
||||
srs_human_trace("send audio raw data failed. ret=%d", ret);
|
||||
goto rtmp_destroy;
|
||||
}
|
||||
|
||||
srs_human_trace("sent packet: type=%s, time=%d, size=%d, codec=%d, rate=%d, sample=%d, channel=%d",
|
||||
srs_human_flv_tag_type2string(SRS_RTMP_TYPE_AUDIO), timestamp, size, sound_format, sound_rate, sound_size,
|
||||
sound_type);
|
||||
|
||||
// @remark, when use encode device, it not need to sleep.
|
||||
usleep(1000 * time_delta);
|
||||
}
|
||||
|
||||
rtmp_destroy:
|
||||
srs_rtmp_destroy(rtmp);
|
||||
close(raw_fd);
|
||||
free(audio_raw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -166,7 +166,7 @@ int main(int argc, char** argv)
|
|||
|
||||
if (srs_audio_write_raw_frame(rtmp,
|
||||
sound_format, sound_rate, sound_size, sound_type,
|
||||
0, data, size, timestamp) != 0
|
||||
data, size, timestamp) != 0
|
||||
) {
|
||||
srs_human_trace("send audio raw data failed.");
|
||||
goto rtmp_destroy;
|
||||
|
|
|
@ -166,16 +166,16 @@ int main(int argc, char** argv)
|
|||
}
|
||||
|
||||
// send out the h264 packet over RTMP
|
||||
int error = srs_h264_write_raw_frames(rtmp, data, size, dts, pts);
|
||||
if (error != 0) {
|
||||
if (srs_h264_is_dvbsp_error(error)) {
|
||||
srs_human_trace("ignore drop video error, code=%d", error);
|
||||
} else if (srs_h264_is_duplicated_sps_error(error)) {
|
||||
srs_human_trace("ignore duplicated sps, code=%d", error);
|
||||
} else if (srs_h264_is_duplicated_pps_error(error)) {
|
||||
srs_human_trace("ignore duplicated pps, code=%d", error);
|
||||
int ret = srs_h264_write_raw_frames(rtmp, data, size, dts, pts);
|
||||
if (ret != 0) {
|
||||
if (srs_h264_is_dvbsp_error(ret)) {
|
||||
srs_human_trace("ignore drop video error, code=%d", ret);
|
||||
} else if (srs_h264_is_duplicated_sps_error(ret)) {
|
||||
srs_human_trace("ignore duplicated sps, code=%d", ret);
|
||||
} else if (srs_h264_is_duplicated_pps_error(ret)) {
|
||||
srs_human_trace("ignore duplicated pps, code=%d", ret);
|
||||
} else {
|
||||
srs_human_trace("send h264 raw data failed.");
|
||||
srs_human_trace("send h264 raw data failed. ret=%d", ret);
|
||||
goto rtmp_destroy;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -249,9 +249,6 @@ int SrsAvcAacCodec::audio_aac_demux(char* data, int size, SrsCodecSample* sample
|
|||
return ret;
|
||||
}
|
||||
|
||||
// aac_profile = audioObjectType - 1
|
||||
aac_profile--;
|
||||
|
||||
// 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
|
||||
//
|
||||
|
|
|
@ -38,25 +38,6 @@ class SrsAmf0Object;
|
|||
#define __SRS_SRS_MAX_CODEC_SAMPLE 128
|
||||
#define __SRS_AAC_SAMPLE_RATE_UNSET 15
|
||||
|
||||
/**
|
||||
* the FLV/RTMP supported audio sample rate.
|
||||
* 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
|
||||
{
|
||||
// set to the max value to reserved, for array map.
|
||||
SrsCodecAudioSampleRateReserved = 4,
|
||||
|
||||
SrsCodecAudioSampleRate5512 = 0,
|
||||
SrsCodecAudioSampleRate11025 = 1,
|
||||
SrsCodecAudioSampleRate22050 = 2,
|
||||
SrsCodecAudioSampleRate44100 = 3,
|
||||
};
|
||||
|
||||
/**
|
||||
* the FLV/RTMP supported audio sample size.
|
||||
* Size of each audio sample. This parameter only pertains to
|
||||
|
@ -224,8 +205,9 @@ public:
|
|||
public:
|
||||
/**
|
||||
* audio specified
|
||||
* 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.
|
||||
* 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;
|
||||
/**
|
||||
|
|
|
@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
// current release version
|
||||
#define VERSION_MAJOR 2
|
||||
#define VERSION_MINOR 0
|
||||
#define VERSION_REVISION 30
|
||||
#define VERSION_REVISION 31
|
||||
// server info.
|
||||
#define RTMP_SIG_SRS_KEY "SRS"
|
||||
#define RTMP_SIG_SRS_ROLE "origin/edge server"
|
||||
|
|
|
@ -144,6 +144,25 @@ enum SrsCodecAudio
|
|||
SrsCodecAudioReservedDeviceSpecificSound = 15,
|
||||
};
|
||||
|
||||
/**
|
||||
* the FLV/RTMP supported audio sample rate.
|
||||
* 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
|
||||
{
|
||||
// set to the max value to reserved, for array map.
|
||||
SrsCodecAudioSampleRateReserved = 4,
|
||||
|
||||
SrsCodecAudioSampleRate5512 = 0,
|
||||
SrsCodecAudioSampleRate11025 = 1,
|
||||
SrsCodecAudioSampleRate22050 = 2,
|
||||
SrsCodecAudioSampleRate44100 = 3,
|
||||
};
|
||||
|
||||
/**
|
||||
* Annex E. The FLV File Format
|
||||
* @see SrsAvcAacCodec for the media stream codec.
|
||||
|
|
|
@ -189,6 +189,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
#define ERROR_H264_DROP_BEFORE_SPS_PPS 3043
|
||||
#define ERROR_H264_DUPLICATED_SPS 3044
|
||||
#define ERROR_H264_DUPLICATED_PPS 3045
|
||||
#define ERROR_AAC_REQUIRED_ADTS 3046
|
||||
#define ERROR_AAC_ADTS_HEADER 3047
|
||||
#define ERROR_AAC_DATA_INVALID 3048
|
||||
|
||||
/**
|
||||
* whether the error code is an system control error.
|
||||
|
|
|
@ -75,7 +75,7 @@ struct Context
|
|||
int stream_id;
|
||||
|
||||
// for h264 raw stream,
|
||||
// see: https://github.com/winlinvip/simple-rtmp-server/issues/66#issuecomment-62240521
|
||||
// @see: https://github.com/winlinvip/simple-rtmp-server/issues/66#issuecomment-62240521
|
||||
SrsStream h264_raw_stream;
|
||||
// about SPS, @see: 7.3.2.1.1, H.264-AVC-ISO_IEC_14496-10-2012.pdf, page 62
|
||||
std::string h264_sps;
|
||||
|
@ -87,6 +87,11 @@ struct Context
|
|||
// @see https://github.com/winlinvip/simple-rtmp-server/issues/204
|
||||
bool h264_sps_changed;
|
||||
bool h264_pps_changed;
|
||||
// for aac raw stream,
|
||||
// @see: https://github.com/winlinvip/simple-rtmp-server/issues/212#issuecomment-64146250
|
||||
SrsStream aac_raw_stream;
|
||||
// the aac sequence header.
|
||||
std::string aac_specific_config;
|
||||
|
||||
Context() {
|
||||
rtmp = NULL;
|
||||
|
@ -859,22 +864,18 @@ int srs_rtmp_write_packet(srs_rtmp_t rtmp, char type, u_int32_t timestamp, char*
|
|||
}
|
||||
|
||||
/**
|
||||
* write audio raw frame to SRS.
|
||||
* directly write a audio frame.
|
||||
*/
|
||||
int srs_audio_write_raw_frame(srs_rtmp_t rtmp,
|
||||
int __srs_write_audio_raw_frame(Context* context,
|
||||
char sound_format, char sound_rate, char sound_size, char sound_type,
|
||||
char aac_packet_type, char* frame, int frame_size, u_int32_t timestamp
|
||||
) {
|
||||
Context* context = (Context*)rtmp;
|
||||
srs_assert(context);
|
||||
|
||||
// TODO: FIXME: for aac, must send the sequence header first.
|
||||
|
||||
// for audio frame, there is 1 or 2 bytes header:
|
||||
// 1bytes, SoundFormat|SoundRate|SoundSize|SoundType
|
||||
// 1bytes, AACPacketType for SoundFormat == 10
|
||||
// 1bytes, AACPacketType for SoundFormat == 10, 0 is sequence header.
|
||||
int size = frame_size + 1;
|
||||
if (aac_packet_type == SrsCodecAudioAAC) {
|
||||
if (sound_format == SrsCodecAudioAAC) {
|
||||
size += 1;
|
||||
}
|
||||
char* data = new char[size];
|
||||
|
@ -887,7 +888,7 @@ int srs_audio_write_raw_frame(srs_rtmp_t rtmp,
|
|||
|
||||
*p++ = audio_header;
|
||||
|
||||
if (aac_packet_type == SrsCodecAudioAAC) {
|
||||
if (sound_format == SrsCodecAudioAAC) {
|
||||
*p++ = aac_packet_type;
|
||||
}
|
||||
|
||||
|
@ -896,6 +897,278 @@ int srs_audio_write_raw_frame(srs_rtmp_t rtmp,
|
|||
return srs_rtmp_write_packet(context, SRS_RTMP_TYPE_AUDIO, timestamp, data, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* write aac frame in adts.
|
||||
*/
|
||||
int __srs_write_aac_adts_frame(Context* context,
|
||||
char sound_format, char sound_rate, char sound_size, char sound_type,
|
||||
char aac_profile, char aac_samplerate, char aac_channel,
|
||||
char* frame, int frame_size, u_int32_t timestamp
|
||||
) {
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
// override the aac samplerate by user specified.
|
||||
// @see https://github.com/winlinvip/simple-rtmp-server/issues/212#issuecomment-64146899
|
||||
switch (sound_rate) {
|
||||
case SrsCodecAudioSampleRate11025:
|
||||
aac_samplerate = 0x0a; break;
|
||||
case SrsCodecAudioSampleRate22050:
|
||||
aac_samplerate = 0x07; break;
|
||||
case SrsCodecAudioSampleRate44100:
|
||||
aac_samplerate = 0x04; break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// send out aac sequence header if not sent.
|
||||
if (context->aac_specific_config.empty()) {
|
||||
char ch = 0;
|
||||
// @see aac-mp4a-format-ISO_IEC_14496-3+2001.pdf
|
||||
// AudioSpecificConfig (), page 33
|
||||
// 1.6.2.1 AudioSpecificConfig
|
||||
// audioObjectType; 5 bslbf
|
||||
ch = (aac_profile << 3) & 0xf8;
|
||||
// 3bits left.
|
||||
|
||||
// samplingFrequencyIndex; 4 bslbf
|
||||
ch |= (aac_samplerate >> 1) & 0x07;
|
||||
context->aac_specific_config += ch;
|
||||
ch = (aac_samplerate << 7) & 0x80;
|
||||
if (aac_samplerate == 0x0f) {
|
||||
return ERROR_AAC_DATA_INVALID;
|
||||
}
|
||||
// 7bits left.
|
||||
|
||||
// channelConfiguration; 4 bslbf
|
||||
ch |= (aac_channel << 3) & 0x70;
|
||||
// 3bits left.
|
||||
|
||||
// only support aac profile 1-4.
|
||||
if (aac_profile < 1 || aac_profile > 4) {
|
||||
return ERROR_AAC_DATA_INVALID;
|
||||
}
|
||||
// GASpecificConfig(), page 451
|
||||
// 4.4.1 Decoder configuration (GASpecificConfig)
|
||||
// frameLengthFlag; 1 bslbf
|
||||
// dependsOnCoreCoder; 1 bslbf
|
||||
// extensionFlag; 1 bslbf
|
||||
context->aac_specific_config += ch;
|
||||
|
||||
if ((ret = __srs_write_audio_raw_frame(context,
|
||||
sound_format, sound_rate, sound_size, sound_type,
|
||||
0, (char*)context->aac_specific_config.data(),
|
||||
context->aac_specific_config.length(),
|
||||
timestamp)) != ERROR_SUCCESS
|
||||
) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return __srs_write_audio_raw_frame(context,
|
||||
sound_format, sound_rate, sound_size, sound_type,
|
||||
1, frame, frame_size, timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* write aac frames in adts.
|
||||
*/
|
||||
int __srs_write_aac_adts_frames(Context* context,
|
||||
char sound_format, char sound_rate, char sound_size, char sound_type,
|
||||
char* frame, int frame_size, u_int32_t timestamp
|
||||
) {
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
SrsStream* stream = &context->aac_raw_stream;
|
||||
if ((ret = stream->initialize(frame, frame_size)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
while (!stream->empty()) {
|
||||
int adts_header_start = stream->pos();
|
||||
|
||||
// decode the ADTS.
|
||||
// @see aac-mp4a-format-ISO_IEC_14496-3+2001.pdf, page 75,
|
||||
// 1.A.2.2 Audio_Data_Transport_Stream frame, ADTS
|
||||
// @see https://github.com/winlinvip/simple-rtmp-server/issues/212#issuecomment-64145885
|
||||
// byte_alignment()
|
||||
|
||||
// adts_fixed_header:
|
||||
// 12bits syncword,
|
||||
// 16bits left.
|
||||
// adts_variable_header:
|
||||
// 28bits
|
||||
// 12+16+28=56bits
|
||||
// adts_error_check:
|
||||
// 16bits if protection_absent
|
||||
// 56+16=72bits
|
||||
// if protection_absent:
|
||||
// require(7bytes)=56bits
|
||||
// else
|
||||
// require(9bytes)=72bits
|
||||
if (!stream->require(7)) {
|
||||
return ERROR_AAC_ADTS_HEADER;
|
||||
}
|
||||
|
||||
// for aac, the frame must be ADTS format.
|
||||
if (!srs_aac_startswith_adts(stream)) {
|
||||
return ERROR_AAC_REQUIRED_ADTS;
|
||||
}
|
||||
|
||||
// Syncword 12 bslbf
|
||||
stream->read_1bytes();
|
||||
// 4bits left.
|
||||
// adts_fixed_header(), 1.A.2.2.1 Fixed Header of ADTS
|
||||
// ID 1 bslbf
|
||||
// Layer 2 uimsbf
|
||||
// protection_absent 1 bslbf
|
||||
int8_t fh0 = (stream->read_1bytes() & 0x0f);
|
||||
/*int8_t fh_id = (fh0 >> 3) & 0x01;*/
|
||||
/*int8_t fh_layer = (fh0 >> 1) & 0x03;*/
|
||||
int8_t fh_protection_absent = fh0 & 0x01;
|
||||
|
||||
int16_t fh1 = stream->read_2bytes();
|
||||
// Profile_ObjectType 2 uimsbf
|
||||
// sampling_frequency_index 4 uimsbf
|
||||
// private_bit 1 bslbf
|
||||
// channel_configuration 3 uimsbf
|
||||
// original/copy 1 bslbf
|
||||
// home 1 bslbf
|
||||
int8_t fh_Profile_ObjectType = (fh1 >> 14) & 0x03;
|
||||
int8_t fh_sampling_frequency_index = (fh1 >> 10) & 0x0f;
|
||||
/*int8_t fh_private_bit = (fh1 >> 9) & 0x01;*/
|
||||
int8_t fh_channel_configuration = (fh1 >> 6) & 0x07;
|
||||
/*int8_t fh_original = (fh1 >> 5) & 0x01;*/
|
||||
/*int8_t fh_home = (fh1 >> 4) & 0x01;*/
|
||||
// @remark, Emphasis is removed,
|
||||
// @see https://github.com/winlinvip/simple-rtmp-server/issues/212#issuecomment-64154736
|
||||
//int8_t fh_Emphasis = (fh1 >> 2) & 0x03;
|
||||
// 4bits left.
|
||||
// adts_variable_header(), 1.A.2.2.2 Variable Header of ADTS
|
||||
// copyright_identification_bit 1 bslbf
|
||||
// copyright_identification_start 1 bslbf
|
||||
/*int8_t fh_copyright_identification_bit = (fh1 >> 3) & 0x01;*/
|
||||
/*int8_t fh_copyright_identification_start = (fh1 >> 2) & 0x01;*/
|
||||
// aac_frame_length 13 bslbf: Length of the frame including headers and error_check in bytes.
|
||||
// use the left 2bits as the 13 and 12 bit,
|
||||
// the aac_frame_length is 13bits, so we move 13-2=11.
|
||||
int16_t fh_aac_frame_length = (fh1 << 11) & 0x0800;
|
||||
|
||||
int32_t fh2 = stream->read_3bytes();
|
||||
// aac_frame_length 13 bslbf: consume the first 13-2=11bits
|
||||
// the fh2 is 24bits, so we move right 24-11=13.
|
||||
fh_aac_frame_length |= (fh2 >> 13) & 0x07ff;
|
||||
// adts_buffer_fullness 11 bslbf
|
||||
/*int16_t fh_adts_buffer_fullness = (fh2 >> 2) & 0x7ff;*/
|
||||
// no_raw_data_blocks_in_frame 2 uimsbf
|
||||
/*int16_t fh_no_raw_data_blocks_in_frame = fh2 & 0x03;*/
|
||||
// adts_error_check(), 1.A.2.2.3 Error detection
|
||||
if (!fh_protection_absent) {
|
||||
if (!stream->require(2)) {
|
||||
return ERROR_AAC_ADTS_HEADER;
|
||||
}
|
||||
// crc_check 16 Rpchof
|
||||
/*int16_t crc_check = */stream->read_2bytes();
|
||||
}
|
||||
|
||||
// TODO: check the fh_sampling_frequency_index
|
||||
// TODO: check the fh_channel_configuration
|
||||
|
||||
// raw_data_blocks
|
||||
int adts_header_size = stream->pos() - adts_header_start;
|
||||
int raw_data_size = fh_aac_frame_length - adts_header_size;
|
||||
if (!stream->require(raw_data_size)) {
|
||||
return ERROR_AAC_ADTS_HEADER;
|
||||
}
|
||||
|
||||
char* raw_data = stream->data() + stream->pos();
|
||||
if ((ret = __srs_write_aac_adts_frame(context,
|
||||
sound_format, sound_rate, sound_size, sound_type,
|
||||
fh_Profile_ObjectType, fh_sampling_frequency_index, fh_channel_configuration,
|
||||
raw_data, raw_data_size, timestamp)) != ERROR_SUCCESS
|
||||
) {
|
||||
return ret;
|
||||
}
|
||||
stream->skip(raw_data_size);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* write audio raw frame to SRS.
|
||||
*/
|
||||
int srs_audio_write_raw_frame(srs_rtmp_t rtmp,
|
||||
char sound_format, char sound_rate, char sound_size, char sound_type,
|
||||
char* frame, int frame_size, u_int32_t timestamp
|
||||
) {
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
Context* context = (Context*)rtmp;
|
||||
srs_assert(context);
|
||||
|
||||
if (sound_format == SrsCodecAudioAAC) {
|
||||
// for aac, the frame must be ADTS format.
|
||||
if (!srs_aac_is_adts(frame, frame_size)) {
|
||||
return ERROR_AAC_REQUIRED_ADTS;
|
||||
}
|
||||
|
||||
// for aac, demux the ADTS to RTMP format.
|
||||
return __srs_write_aac_adts_frames(context,
|
||||
sound_format, sound_rate, sound_size, sound_type,
|
||||
frame, frame_size, timestamp);
|
||||
} else {
|
||||
// for other data, directly write frame.
|
||||
return __srs_write_audio_raw_frame(context,
|
||||
sound_format, sound_rate, sound_size, sound_type,
|
||||
0, frame, frame_size, timestamp);
|
||||
}
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* whether aac raw data is in adts format,
|
||||
* which bytes sequence matches '1111 1111 1111'B, that is 0xFFF.
|
||||
*/
|
||||
srs_bool srs_aac_is_adts(char* aac_raw_data, int ac_raw_size)
|
||||
{
|
||||
SrsStream stream;
|
||||
if (stream.initialize(aac_raw_data, ac_raw_size) != ERROR_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return srs_aac_startswith_adts(&stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* parse the adts header to get the frame size.
|
||||
*/
|
||||
int srs_aac_adts_frame_size(char* aac_raw_data, int ac_raw_size)
|
||||
{
|
||||
int size = -1;
|
||||
|
||||
if (!srs_aac_is_adts(aac_raw_data, ac_raw_size)) {
|
||||
return size;
|
||||
}
|
||||
|
||||
// adts always 7bytes.
|
||||
if (ac_raw_size <= 7) {
|
||||
return size;
|
||||
}
|
||||
|
||||
// last 2bits
|
||||
int16_t ch3 = aac_raw_data[3];
|
||||
// whole 8bits
|
||||
int16_t ch4 = aac_raw_data[4];
|
||||
// first 3bits
|
||||
int16_t ch5 = aac_raw_data[5];
|
||||
|
||||
size = ((ch3 << 11) & 0x1800) | ((ch4 << 3) & 0x07f8) | ((ch5 >> 5) & 0x0007);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* write h264 packet, with rtmp header.
|
||||
* @param frame_type, SrsCodecVideoAVCFrameKeyFrame or SrsCodecVideoAVCFrameInterFrame.
|
||||
|
@ -1224,22 +1497,22 @@ int srs_h264_write_raw_frames(srs_rtmp_t rtmp,
|
|||
return error_code_return;
|
||||
}
|
||||
|
||||
srs_h264_bool srs_h264_is_dvbsp_error(int error_code)
|
||||
srs_bool srs_h264_is_dvbsp_error(int error_code)
|
||||
{
|
||||
return error_code == ERROR_H264_DROP_BEFORE_SPS_PPS;
|
||||
}
|
||||
|
||||
srs_h264_bool srs_h264_is_duplicated_sps_error(int error_code)
|
||||
srs_bool srs_h264_is_duplicated_sps_error(int error_code)
|
||||
{
|
||||
return error_code == ERROR_H264_DUPLICATED_SPS;
|
||||
}
|
||||
|
||||
srs_h264_bool srs_h264_is_duplicated_pps_error(int error_code)
|
||||
srs_bool srs_h264_is_duplicated_pps_error(int error_code)
|
||||
{
|
||||
return error_code == ERROR_H264_DUPLICATED_PPS;
|
||||
}
|
||||
|
||||
int srs_h264_startswith_annexb(char* h264_raw_data, int h264_raw_size, int* pnb_start_code)
|
||||
srs_bool srs_h264_startswith_annexb(char* h264_raw_data, int h264_raw_size, int* pnb_start_code)
|
||||
{
|
||||
SrsStream stream;
|
||||
if (stream.initialize(h264_raw_data, h264_raw_size) != ERROR_SUCCESS) {
|
||||
|
@ -1417,17 +1690,17 @@ void srs_flv_lseek(srs_flv_t flv, int64_t offset)
|
|||
context->reader.lseek(offset);
|
||||
}
|
||||
|
||||
srs_flv_bool srs_flv_is_eof(int error_code)
|
||||
srs_bool srs_flv_is_eof(int error_code)
|
||||
{
|
||||
return error_code == ERROR_SYSTEM_FILE_EOF;
|
||||
}
|
||||
|
||||
srs_flv_bool srs_flv_is_sequence_header(char* data, int32_t size)
|
||||
srs_bool srs_flv_is_sequence_header(char* data, int32_t size)
|
||||
{
|
||||
return SrsFlvCodec::video_is_sequence_header(data, (int)size);
|
||||
}
|
||||
|
||||
srs_flv_bool srs_flv_is_keyframe(char* data, int32_t size)
|
||||
srs_bool srs_flv_is_keyframe(char* data, int32_t size)
|
||||
{
|
||||
return SrsFlvCodec::video_is_keyframe(data, (int)size);
|
||||
}
|
||||
|
@ -1517,43 +1790,43 @@ int srs_amf0_serialize(srs_amf0_t amf0, char* data, int size)
|
|||
return ret;
|
||||
}
|
||||
|
||||
srs_amf0_bool srs_amf0_is_string(srs_amf0_t amf0)
|
||||
srs_bool srs_amf0_is_string(srs_amf0_t amf0)
|
||||
{
|
||||
SrsAmf0Any* any = (SrsAmf0Any*)amf0;
|
||||
return any->is_string();
|
||||
}
|
||||
|
||||
srs_amf0_bool srs_amf0_is_boolean(srs_amf0_t amf0)
|
||||
srs_bool srs_amf0_is_boolean(srs_amf0_t amf0)
|
||||
{
|
||||
SrsAmf0Any* any = (SrsAmf0Any*)amf0;
|
||||
return any->is_boolean();
|
||||
}
|
||||
|
||||
srs_amf0_bool srs_amf0_is_number(srs_amf0_t amf0)
|
||||
srs_bool srs_amf0_is_number(srs_amf0_t amf0)
|
||||
{
|
||||
SrsAmf0Any* any = (SrsAmf0Any*)amf0;
|
||||
return any->is_number();
|
||||
}
|
||||
|
||||
srs_amf0_bool srs_amf0_is_null(srs_amf0_t amf0)
|
||||
srs_bool srs_amf0_is_null(srs_amf0_t amf0)
|
||||
{
|
||||
SrsAmf0Any* any = (SrsAmf0Any*)amf0;
|
||||
return any->is_null();
|
||||
}
|
||||
|
||||
srs_amf0_bool srs_amf0_is_object(srs_amf0_t amf0)
|
||||
srs_bool srs_amf0_is_object(srs_amf0_t amf0)
|
||||
{
|
||||
SrsAmf0Any* any = (SrsAmf0Any*)amf0;
|
||||
return any->is_object();
|
||||
}
|
||||
|
||||
srs_amf0_bool srs_amf0_is_ecma_array(srs_amf0_t amf0)
|
||||
srs_bool srs_amf0_is_ecma_array(srs_amf0_t amf0)
|
||||
{
|
||||
SrsAmf0Any* any = (SrsAmf0Any*)amf0;
|
||||
return any->is_ecma_array();
|
||||
}
|
||||
|
||||
srs_amf0_bool srs_amf0_is_strict_array(srs_amf0_t amf0)
|
||||
srs_bool srs_amf0_is_strict_array(srs_amf0_t amf0)
|
||||
{
|
||||
SrsAmf0Any* any = (SrsAmf0Any*)amf0;
|
||||
return any->is_strict_array();
|
||||
|
@ -1565,7 +1838,7 @@ const char* srs_amf0_to_string(srs_amf0_t amf0)
|
|||
return any->to_str_raw();
|
||||
}
|
||||
|
||||
srs_amf0_bool srs_amf0_to_boolean(srs_amf0_t amf0)
|
||||
srs_bool srs_amf0_to_boolean(srs_amf0_t amf0)
|
||||
{
|
||||
SrsAmf0Any* any = (SrsAmf0Any*)amf0;
|
||||
return any->to_boolean();
|
||||
|
|
|
@ -84,6 +84,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
extern "C"{
|
||||
#endif
|
||||
|
||||
// typedefs
|
||||
typedef int srs_bool;
|
||||
|
||||
/*************************************************************
|
||||
**************************************************************
|
||||
* srs-librtmp version
|
||||
|
@ -303,12 +306,15 @@ extern int srs_rtmp_write_packet(srs_rtmp_t rtmp,
|
|||
* @param sound_type Mono or stereo sound
|
||||
* 0 = Mono sound
|
||||
* 1 = Stereo sound
|
||||
* @param aac_packet_type The following values are defined:
|
||||
* 0 = AAC sequence header
|
||||
* 1 = AAC raw
|
||||
* @param timestamp The timestamp of audio.
|
||||
*
|
||||
* @remark Ignore aac_packet_type if not aac(sound_format!=10).
|
||||
* @example /trunk/research/librtmp/srs_aac_raw_publish.c
|
||||
* @example /trunk/research/librtmp/srs_audio_raw_publish.c
|
||||
*
|
||||
* @remark for aac, the frame must be in ADTS format.
|
||||
* @see aac-mp4a-format-ISO_IEC_14496-3+2001.pdf, page 75, 1.A.2.2 ADTS
|
||||
* @remark for aac, only support profile 1-4, AAC main/LC/SSR/LTP,
|
||||
* @see aac-mp4a-format-ISO_IEC_14496-3+2001.pdf, page 23, 1.5.1.1 Audio object type
|
||||
*
|
||||
* @see https://github.com/winlinvip/simple-rtmp-server/issues/212
|
||||
* @see E.4.2.1 AUDIODATA of video_file_format_spec_v10_1.pdf
|
||||
|
@ -317,15 +323,38 @@ extern int srs_rtmp_write_packet(srs_rtmp_t rtmp,
|
|||
*/
|
||||
extern int srs_audio_write_raw_frame(srs_rtmp_t rtmp,
|
||||
char sound_format, char sound_rate, char sound_size, char sound_type,
|
||||
char aac_packet_type, char* frame, int frame_size, u_int32_t timestamp
|
||||
char* frame, int frame_size, u_int32_t timestamp
|
||||
);
|
||||
|
||||
/**
|
||||
* whether aac raw data is in adts format,
|
||||
* which bytes sequence matches '1111 1111 1111'B, that is 0xFFF.
|
||||
* @param aac_raw_data the input aac raw data, a encoded aac frame data.
|
||||
* @param ac_raw_size the size of aac raw data.
|
||||
*
|
||||
* @reamrk used to check whether current frame is in adts format.
|
||||
* @see aac-mp4a-format-ISO_IEC_14496-3+2001.pdf, page 75, 1.A.2.2 ADTS
|
||||
* @example /trunk/research/librtmp/srs_aac_raw_publish.c
|
||||
*
|
||||
* @return 0 false; otherwise, true.
|
||||
*/
|
||||
extern srs_bool srs_aac_is_adts(char* aac_raw_data, int ac_raw_size);
|
||||
|
||||
/**
|
||||
* parse the adts header to get the frame size,
|
||||
* which bytes sequence matches '1111 1111 1111'B, that is 0xFFF.
|
||||
* @param aac_raw_data the input aac raw data, a encoded aac frame data.
|
||||
* @param ac_raw_size the size of aac raw data.
|
||||
*
|
||||
* @return failed when <=0 failed; otherwise, ok.
|
||||
*/
|
||||
extern int srs_aac_adts_frame_size(char* aac_raw_data, int ac_raw_size);
|
||||
|
||||
/*************************************************************
|
||||
**************************************************************
|
||||
* h264 raw codec
|
||||
**************************************************************
|
||||
*************************************************************/
|
||||
typedef int srs_h264_bool;
|
||||
/**
|
||||
* write h.264 raw frame over RTMP to rtmp server.
|
||||
* @param frames the input h264 raw data, encoded h.264 I/P/B frames data.
|
||||
|
@ -392,21 +421,21 @@ extern int srs_h264_write_raw_frames(srs_rtmp_t rtmp,
|
|||
* so, when error and reconnect the rtmp, the first video is not sps/pps(sequence header),
|
||||
* this will cause SRS server to disable HLS.
|
||||
*/
|
||||
extern srs_h264_bool srs_h264_is_dvbsp_error(int error_code);
|
||||
extern srs_bool srs_h264_is_dvbsp_error(int error_code);
|
||||
/**
|
||||
* whether error_code is duplicated sps error.
|
||||
*
|
||||
* @see https://github.com/winlinvip/simple-rtmp-server/issues/204
|
||||
* @example /trunk/research/librtmp/srs_h264_raw_publish.c
|
||||
*/
|
||||
extern srs_h264_bool srs_h264_is_duplicated_sps_error(int error_code);
|
||||
extern srs_bool srs_h264_is_duplicated_sps_error(int error_code);
|
||||
/**
|
||||
* whether error_code is duplicated pps error.
|
||||
*
|
||||
* @see https://github.com/winlinvip/simple-rtmp-server/issues/204
|
||||
* @example /trunk/research/librtmp/srs_h264_raw_publish.c
|
||||
*/
|
||||
extern srs_h264_bool srs_h264_is_duplicated_pps_error(int error_code);
|
||||
extern srs_bool srs_h264_is_duplicated_pps_error(int error_code);
|
||||
/**
|
||||
* whether h264 raw data starts with the annexb,
|
||||
* which bytes sequence matches N[00] 00 00 01, where N>=0.
|
||||
|
@ -420,7 +449,7 @@ extern srs_h264_bool srs_h264_is_duplicated_pps_error(int error_code);
|
|||
*
|
||||
* @return 0 false; otherwise, true.
|
||||
*/
|
||||
extern int srs_h264_startswith_annexb(
|
||||
extern srs_bool srs_h264_startswith_annexb(
|
||||
char* h264_raw_data, int h264_raw_size,
|
||||
int* pnb_start_code
|
||||
);
|
||||
|
@ -435,7 +464,6 @@ extern int srs_h264_startswith_annexb(
|
|||
**************************************************************
|
||||
*************************************************************/
|
||||
typedef void* srs_flv_t;
|
||||
typedef int srs_flv_bool;
|
||||
/* open flv file for both read/write. */
|
||||
extern srs_flv_t srs_flv_open_read(const char* file);
|
||||
extern srs_flv_t srs_flv_open_write(const char* file);
|
||||
|
@ -510,20 +538,20 @@ extern int64_t srs_flv_tellg(srs_flv_t flv);
|
|||
extern void srs_flv_lseek(srs_flv_t flv, int64_t offset);
|
||||
/* error code */
|
||||
/* whether the error code indicates EOF */
|
||||
extern srs_flv_bool srs_flv_is_eof(int error_code);
|
||||
extern srs_bool srs_flv_is_eof(int error_code);
|
||||
/* media codec */
|
||||
/**
|
||||
* whether the video body is sequence header
|
||||
* @param data, the data of tag, read by srs_flv_read_tag_data().
|
||||
* @param size, the size of tag, read by srs_flv_read_tag_data().
|
||||
*/
|
||||
extern srs_flv_bool srs_flv_is_sequence_header(char* data, int32_t size);
|
||||
extern srs_bool srs_flv_is_sequence_header(char* data, int32_t size);
|
||||
/**
|
||||
* whether the video body is keyframe
|
||||
* @param data, the data of tag, read by srs_flv_read_tag_data().
|
||||
* @param size, the size of tag, read by srs_flv_read_tag_data().
|
||||
*/
|
||||
extern srs_flv_bool srs_flv_is_keyframe(char* data, int32_t size);
|
||||
extern srs_bool srs_flv_is_keyframe(char* data, int32_t size);
|
||||
|
||||
/*************************************************************
|
||||
**************************************************************
|
||||
|
@ -534,7 +562,6 @@ extern srs_flv_bool srs_flv_is_keyframe(char* data, int32_t size);
|
|||
*************************************************************/
|
||||
/* the output handler. */
|
||||
typedef void* srs_amf0_t;
|
||||
typedef int srs_amf0_bool;
|
||||
typedef double srs_amf0_number;
|
||||
/**
|
||||
* parse amf0 from data.
|
||||
|
@ -552,16 +579,16 @@ extern void srs_amf0_free_bytes(char* data);
|
|||
extern int srs_amf0_size(srs_amf0_t amf0);
|
||||
extern int srs_amf0_serialize(srs_amf0_t amf0, char* data, int size);
|
||||
/* type detecter */
|
||||
extern srs_amf0_bool srs_amf0_is_string(srs_amf0_t amf0);
|
||||
extern srs_amf0_bool srs_amf0_is_boolean(srs_amf0_t amf0);
|
||||
extern srs_amf0_bool srs_amf0_is_number(srs_amf0_t amf0);
|
||||
extern srs_amf0_bool srs_amf0_is_null(srs_amf0_t amf0);
|
||||
extern srs_amf0_bool srs_amf0_is_object(srs_amf0_t amf0);
|
||||
extern srs_amf0_bool srs_amf0_is_ecma_array(srs_amf0_t amf0);
|
||||
extern srs_amf0_bool srs_amf0_is_strict_array(srs_amf0_t amf0);
|
||||
extern srs_bool srs_amf0_is_string(srs_amf0_t amf0);
|
||||
extern srs_bool srs_amf0_is_boolean(srs_amf0_t amf0);
|
||||
extern srs_bool srs_amf0_is_number(srs_amf0_t amf0);
|
||||
extern srs_bool srs_amf0_is_null(srs_amf0_t amf0);
|
||||
extern srs_bool srs_amf0_is_object(srs_amf0_t amf0);
|
||||
extern srs_bool srs_amf0_is_ecma_array(srs_amf0_t amf0);
|
||||
extern srs_bool srs_amf0_is_strict_array(srs_amf0_t amf0);
|
||||
/* value converter */
|
||||
extern const char* srs_amf0_to_string(srs_amf0_t amf0);
|
||||
extern srs_amf0_bool srs_amf0_to_boolean(srs_amf0_t amf0);
|
||||
extern srs_bool srs_amf0_to_boolean(srs_amf0_t amf0);
|
||||
extern srs_amf0_number srs_amf0_to_number(srs_amf0_t amf0);
|
||||
/* value setter */
|
||||
extern void srs_amf0_set_number(srs_amf0_t amf0, srs_amf0_number value);
|
||||
|
|
|
@ -167,12 +167,12 @@ bool srs_avc_startswith_annexb(SrsStream* stream, int* pnb_start_code)
|
|||
}
|
||||
|
||||
// not match
|
||||
if (p[0] != 0x00 || p[1] != 0x00) {
|
||||
if (p[0] != (char)0x00 || p[1] != (char)0x00) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// match N[00] 00 00 01, where N>=0
|
||||
if (p[2] == 0x01) {
|
||||
if (p[2] == (char)0x01) {
|
||||
if (pnb_start_code) {
|
||||
*pnb_start_code = (int)(p - bytes) + 3;
|
||||
}
|
||||
|
@ -185,3 +185,21 @@ bool srs_avc_startswith_annexb(SrsStream* stream, int* pnb_start_code)
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -96,5 +96,12 @@ extern bool srs_bytes_equals(void* pa, void* pb, int size);
|
|||
*/
|
||||
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
|
||||
|
||||
|
|
|
@ -130,6 +130,7 @@ file
|
|||
..\utest\srs_utest_reload.hpp,
|
||||
..\utest\srs_utest_reload.cpp,
|
||||
research readonly separator,
|
||||
..\..\research\librtmp\srs_aac_raw_publish.c,
|
||||
..\..\research\librtmp\srs_audio_raw_publish.c,
|
||||
..\..\research\librtmp\srs_bandwidth_check.c,
|
||||
..\..\research\librtmp\srs_detect_rtmp.c,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue