mirror of
https://github.com/ossrs/srs.git
synced 2025-02-13 03:41:55 +00:00
Merge branch 'srs.master'
This commit is contained in:
commit
0ce0df3fb4
7 changed files with 301 additions and 4 deletions
|
@ -482,6 +482,7 @@ Supported operating systems and hardware:
|
|||
* 2013-10-17, Created.<br/>
|
||||
|
||||
## History
|
||||
* v2.0, 2014-11-20, fix [#212](https://github.com/winlinvip/simple-rtmp-server/issues/212), support publish audio raw frames. 2.0.27
|
||||
* v2.0, 2014-11-19, fix [#213](https://github.com/winlinvip/simple-rtmp-server/issues/213), support compile [srs-librtmp on windows](https://github.com/winlinvip/srs.librtmp), [bug #213](https://github.com/winlinvip/simple-rtmp-server/issues/213). 2.0.26
|
||||
* v2.0, 2014-11-18, all wiki translated to English. 2.0.23.
|
||||
* v2.0, 2014-11-15, fix [#204](https://github.com/winlinvip/simple-rtmp-server/issues/204), srs-librtmp drop duplicated sps/pps(sequence header). 2.0.22.
|
||||
|
|
|
@ -6,7 +6,8 @@ else
|
|||
ST_ALL = objs/srs_flv_parser \
|
||||
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_bandwidth_check objs/srs_h264_raw_publish \
|
||||
objs/srs_audio_raw_publish
|
||||
endif
|
||||
|
||||
.PHONY: default clean help ssl nossl
|
||||
|
@ -24,6 +25,7 @@ help:
|
|||
@echo " srs_flv_injecter inject keyframes information to metadata."
|
||||
@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_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."
|
||||
|
@ -85,6 +87,9 @@ objs/srs_publish: srs_publish.c $(SRS_RESEARCH_DEPS) $(SRS_LIBRTMP_I) $(SRS_LIBR
|
|||
objs/srs_h264_raw_publish: srs_h264_raw_publish.c $(SRS_RESEARCH_DEPS) $(SRS_LIBRTMP_I) $(SRS_LIBRTMP_L) $(SRS_LIBSSL_L)
|
||||
$(GCC) srs_h264_raw_publish.c $(SRS_LIBRTMP_L) $(SRS_LIBSSL_L) $(EXTRA_CXX_FLAG) -o objs/srs_h264_raw_publish
|
||||
|
||||
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_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
|
||||
|
||||
|
|
190
trunk/research/librtmp/srs_audio_raw_publish.c
Normal file
190
trunk/research/librtmp/srs_audio_raw_publish.c
Normal file
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
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_audio_raw_publish.c ../../objs/lib/srs_librtmp.a -g -O0 -lstdc++ -o srs_audio_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* audio_raw, int file_size, char** pp, char** pdata, int* psize)
|
||||
{
|
||||
char* p = *pp;
|
||||
|
||||
if (file_size - (p - audio_raw) < 168) {
|
||||
srs_lib_trace("audio must be 160+8 bytes. left %d bytes.",
|
||||
file_size - (p - audio_raw));
|
||||
return - 1;
|
||||
}
|
||||
|
||||
// ignore 8bytes vendor specific header.
|
||||
p += 8;
|
||||
|
||||
// 160 bytes audio frame
|
||||
*pdata = p;
|
||||
*psize = 160;
|
||||
|
||||
// next frame.
|
||||
*pp = p + *psize;
|
||||
|
||||
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.pcm rtmp://127.0.0.1:1935/live/livestream\n", argv[0]);
|
||||
printf("Where the file: http://winlinvip.github.io/srs.release/3rdparty/audio.raw.pcm\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_lib_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_lib_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_lib_trace("audio raw file %s empty.", raw_file);
|
||||
goto rtmp_destroy;
|
||||
}
|
||||
srs_lib_trace("read entirely audio raw file, size=%dKB", (int)(file_size / 1024));
|
||||
|
||||
char* audio_raw = (char*)malloc(file_size);
|
||||
if (!audio_raw) {
|
||||
srs_lib_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_lib_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_simple_handshake(rtmp) != 0) {
|
||||
srs_lib_trace("simple handshake failed.");
|
||||
goto rtmp_destroy;
|
||||
}
|
||||
srs_lib_trace("simple handshake success");
|
||||
|
||||
if (srs_connect_app(rtmp) != 0) {
|
||||
srs_lib_trace("connect vhost/app failed.");
|
||||
goto rtmp_destroy;
|
||||
}
|
||||
srs_lib_trace("connect vhost/app success");
|
||||
|
||||
if (srs_publish_stream(rtmp) != 0) {
|
||||
srs_lib_trace("publish stream failed.");
|
||||
goto rtmp_destroy;
|
||||
}
|
||||
srs_lib_trace("publish stream success");
|
||||
|
||||
u_int32_t timestamp = 0;
|
||||
u_int32_t time_delta = 17;
|
||||
// @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_lib_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 = 1;
|
||||
// 3 = 44 kHz
|
||||
char sound_rate = 3;
|
||||
// 1 = 16-bit samples
|
||||
char sound_size = 1;
|
||||
// 1 = Stereo sound
|
||||
char sound_type = 1;
|
||||
|
||||
timestamp += time_delta;
|
||||
|
||||
if (srs_audio_write_raw_frame(rtmp,
|
||||
sound_format, sound_rate, sound_size, sound_type,
|
||||
0, data, size, timestamp) != 0
|
||||
) {
|
||||
srs_lib_trace("send audio raw data failed.");
|
||||
goto rtmp_destroy;
|
||||
}
|
||||
|
||||
srs_lib_trace("sent packet: type=%s, time=%d, size=%d, codec=%d, rate=%d, sample=%d, channel=%d",
|
||||
srs_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;
|
||||
}
|
||||
|
|
@ -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 26
|
||||
#define VERSION_REVISION 27
|
||||
// server info.
|
||||
#define RTMP_SIG_SRS_KEY "SRS"
|
||||
#define RTMP_SIG_SRS_ROLE "origin/edge server"
|
||||
|
|
|
@ -1438,6 +1438,46 @@ char* srs_amf0_human_print(srs_amf0_t amf0, char** pdata, int* psize)
|
|||
return any->human_print(pdata, psize);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 aac_packet_type, char* frame, int frame_size, u_int32_t timestamp
|
||||
) {
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
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
|
||||
int size = frame_size + 1;
|
||||
if (aac_packet_type == SrsCodecAudioAAC) {
|
||||
size += 1;
|
||||
}
|
||||
char* data = new char[size];
|
||||
char* p = data;
|
||||
|
||||
u_int8_t audio_header = sound_type & 0x01;
|
||||
audio_header |= (sound_size << 1) & 0x02;
|
||||
audio_header |= (sound_rate << 2) & 0x0c;
|
||||
audio_header |= (sound_format << 4) & 0xf0;
|
||||
|
||||
*p++ = audio_header;
|
||||
|
||||
if (aac_packet_type == SrsCodecAudioAAC) {
|
||||
*p++ = aac_packet_type;
|
||||
}
|
||||
|
||||
memcpy(p, frame, frame_size);
|
||||
|
||||
return srs_write_packet(context, SRS_RTMP_TYPE_AUDIO, timestamp, data, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* write h264 packet, with rtmp header.
|
||||
* @param frame_type, SrsCodecVideoAVCFrameKeyFrame or SrsCodecVideoAVCFrameInterFrame.
|
||||
|
@ -1458,7 +1498,6 @@ int __srs_write_h264_packet(Context* context,
|
|||
// @see: E.4.3 Video Tags, video_file_format_spec_v10_1.pdf, page 78
|
||||
int size = h264_raw_size + 5;
|
||||
char* data = new char[size];
|
||||
memcpy(data + 5, h264_raw_data, h264_raw_size);
|
||||
char* p = data;
|
||||
|
||||
// @see: E.4.3 Video Tags, video_file_format_spec_v10_1.pdf, page 78
|
||||
|
@ -1480,6 +1519,9 @@ int __srs_write_h264_packet(Context* context,
|
|||
*p++ = pp[1];
|
||||
*p++ = pp[0];
|
||||
|
||||
// h.264 raw data.
|
||||
memcpy(p, h264_raw_data, h264_raw_size);
|
||||
|
||||
return srs_write_packet(context, SRS_RTMP_TYPE_VIDEO, timestamp, data, size);
|
||||
}
|
||||
|
||||
|
|
|
@ -461,6 +461,64 @@ extern void srs_amf0_strict_array_append(srs_amf0_t amf0, srs_amf0_t value);
|
|||
*/
|
||||
extern char* srs_amf0_human_print(srs_amf0_t amf0, char** pdata, int* psize);
|
||||
|
||||
/*************************************************************
|
||||
**************************************************************
|
||||
* audio raw codec
|
||||
**************************************************************
|
||||
*************************************************************/
|
||||
/**
|
||||
* write an audio raw frame to srs.
|
||||
* not similar to h.264 video, the audio never aggregated, always
|
||||
* encoded one frame by one, so this api is used to write a frame.
|
||||
*
|
||||
* @param sound_format Format of SoundData. The following values are defined:
|
||||
* 0 = Linear PCM, platform endian
|
||||
* 1 = ADPCM
|
||||
* 2 = MP3
|
||||
* 3 = Linear PCM, little endian
|
||||
* 4 = Nellymoser 16 kHz mono
|
||||
* 5 = Nellymoser 8 kHz mono
|
||||
* 6 = Nellymoser
|
||||
* 7 = G.711 A-law logarithmic PCM
|
||||
* 8 = G.711 mu-law logarithmic PCM
|
||||
* 9 = reserved
|
||||
* 10 = AAC
|
||||
* 11 = Speex
|
||||
* 14 = MP3 8 kHz
|
||||
* 15 = Device-specific sound
|
||||
* Formats 7, 8, 14, and 15 are reserved.
|
||||
* AAC is supported in Flash Player 9,0,115,0 and higher.
|
||||
* Speex is supported in Flash Player 10 and higher.
|
||||
* @param sound_rate Sampling rate. The following values are defined:
|
||||
* 0 = 5.5 kHz
|
||||
* 1 = 11 kHz
|
||||
* 2 = 22 kHz
|
||||
* 3 = 44 kHz
|
||||
* @param sound_size Size of each audio sample. This parameter only pertains to
|
||||
* uncompressed formats. Compressed formats always decode
|
||||
* to 16 bits internally.
|
||||
* 0 = 8-bit samples
|
||||
* 1 = 16-bit samples
|
||||
* @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).
|
||||
*
|
||||
* @see https://github.com/winlinvip/simple-rtmp-server/issues/212
|
||||
* @see E.4.2.1 AUDIODATA of video_file_format_spec_v10_1.pdf
|
||||
*
|
||||
* @return 0, success; otherswise, failed.
|
||||
*/
|
||||
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
|
||||
);
|
||||
|
||||
/*************************************************************
|
||||
**************************************************************
|
||||
* h264 raw codec
|
||||
|
@ -474,7 +532,7 @@ typedef int srs_h264_bool;
|
|||
* each frame prefixed h.264 annexb header, by N[00] 00 00 01, where N>=0,
|
||||
* for instance, frame = header(00 00 00 01) + payload(67 42 80 29 95 A0 14 01 6E 40)
|
||||
* about annexb, @see H.264-AVC-ISO_IEC_14496-10.pdf, page 211.
|
||||
* @paam frames_size the size of h264 raw data.
|
||||
* @param frames_size the size of h264 raw data.
|
||||
* assert frames_size > 0, at least has 1 bytes header.
|
||||
* @param dts the dts of h.264 raw data.
|
||||
* @param pts the pts of h.264 raw data.
|
||||
|
|
|
@ -128,6 +128,7 @@ file
|
|||
..\utest\srs_utest_reload.hpp,
|
||||
..\utest\srs_utest_reload.cpp,
|
||||
research readonly separator,
|
||||
..\..\research\librtmp\srs_audio_raw_publish.c,
|
||||
..\..\research\librtmp\srs_bandwidth_check.c,
|
||||
..\..\research\librtmp\srs_detect_rtmp.c,
|
||||
..\..\research\librtmp\srs_flv_injecter.c,
|
||||
|
|
Loading…
Reference in a new issue