From c0233542bf16dc0167e9b203ff05b9393241d5e6 Mon Sep 17 00:00:00 2001 From: winlin Date: Sun, 18 Jan 2015 22:51:07 +0800 Subject: [PATCH] for #293, add aac encoder for http aac stream. --- trunk/configure | 2 +- trunk/src/app/srs_app_http.cpp | 2 +- trunk/src/app/srs_app_http_conn.cpp | 147 ++++++++++++--- trunk/src/app/srs_app_http_conn.hpp | 58 +++++- trunk/src/kernel/srs_kernel_aac.cpp | 246 ++++++++++++++++++++++++++ trunk/src/kernel/srs_kernel_aac.hpp | 94 ++++++++++ trunk/src/kernel/srs_kernel_error.hpp | 1 + trunk/src/srs/srs.upp | 2 + 8 files changed, 525 insertions(+), 27 deletions(-) create mode 100644 trunk/src/kernel/srs_kernel_aac.cpp create mode 100644 trunk/src/kernel/srs_kernel_aac.hpp diff --git a/trunk/configure b/trunk/configure index 47265e6fbb..24d595a50f 100755 --- a/trunk/configure +++ b/trunk/configure @@ -365,7 +365,7 @@ MODULE_DEPENDS=("CORE") ModuleLibIncs=(${SRS_OBJS_DIR}) MODULE_FILES=("srs_kernel_error" "srs_kernel_log" "srs_kernel_stream" "srs_kernel_utility" "srs_kernel_flv" "srs_kernel_codec" "srs_kernel_file" - "srs_kernel_consts") + "srs_kernel_consts" "srs_kernel_aac") KERNEL_INCS="src/kernel"; MODULE_DIR=${KERNEL_INCS} . auto/modules.sh KERNEL_OBJS="${MODULE_OBJS[@]}" # diff --git a/trunk/src/app/srs_app_http.cpp b/trunk/src/app/srs_app_http.cpp index 22f4fe718b..ba235dba4c 100644 --- a/trunk/src/app/srs_app_http.cpp +++ b/trunk/src/app/srs_app_http.cpp @@ -371,7 +371,7 @@ int SrsGoHttpFileServer::serve_file(ISrsGoHttpResponseWriter* w, SrsHttpMessage* } if (true) { - ssize_t pos; + size_t pos; std::string ext = fullpath; if ((pos = ext.rfind(".")) != string::npos) { ext = ext.substr(pos); diff --git a/trunk/src/app/srs_app_http_conn.cpp b/trunk/src/app/srs_app_http_conn.cpp index 08cbebf70d..36ddf4f3f6 100644 --- a/trunk/src/app/srs_app_http_conn.cpp +++ b/trunk/src/app/srs_app_http_conn.cpp @@ -44,6 +44,7 @@ using namespace std; #include #include #include +#include SrsVodStream::SrsVodStream(string root_dir) : SrsGoHttpFileServer(root_dir) @@ -138,35 +139,120 @@ int SrsVodStream::serve_flv_stream(ISrsGoHttpResponseWriter* w, SrsHttpMessage* return ret; } -SrsFlvStreamWriter::SrsFlvStreamWriter(ISrsGoHttpResponseWriter* w) +ISrsStreamEncoder::ISrsStreamEncoder() +{ +} + +ISrsStreamEncoder::~ISrsStreamEncoder() +{ +} + +SrsFlvStreamEncoder::SrsFlvStreamEncoder() +{ + enc = new SrsFlvEncoder(); +} + +SrsFlvStreamEncoder::~SrsFlvStreamEncoder() +{ + srs_freep(enc); +} + +int SrsFlvStreamEncoder::initialize(SrsFileWriter* w) +{ + int ret = ERROR_SUCCESS; + + if ((ret = enc->initialize(w)) != ERROR_SUCCESS) { + return ret; + } + + // write flv header. + if ((ret = enc->write_header()) != ERROR_SUCCESS) { + return ret; + } + + return ret; +} + +int SrsFlvStreamEncoder::write_audio(int64_t timestamp, char* data, int size) +{ + return enc->write_audio(timestamp, data, size); +} + +int SrsFlvStreamEncoder::write_video(int64_t timestamp, char* data, int size) +{ + return enc->write_video(timestamp, data, size); +} + +int SrsFlvStreamEncoder::write_metadata(int64_t timestamp, char* data, int size) +{ + return enc->write_metadata(timestamp, data, size); +} + +SrsAacStreamEncoder::SrsAacStreamEncoder() +{ + enc = new SrsAacEncoder(); +} + +SrsAacStreamEncoder::~SrsAacStreamEncoder() +{ + srs_freep(enc); +} + +int SrsAacStreamEncoder::initialize(SrsFileWriter* w) +{ + int ret = ERROR_SUCCESS; + + if ((ret = enc->initialize(w)) != ERROR_SUCCESS) { + return ret; + } + + return ret; +} + +int SrsAacStreamEncoder::write_audio(int64_t timestamp, char* data, int size) +{ + return enc->write_audio(timestamp, data, size); +} + +int SrsAacStreamEncoder::write_video(int64_t timestamp, char* data, int size) +{ + return enc->write_video(timestamp, data, size); +} + +int SrsAacStreamEncoder::write_metadata(int64_t timestamp, char* data, int size) +{ + return enc->write_metadata(timestamp, data, size); +} + +SrsStreamWriter::SrsStreamWriter(ISrsGoHttpResponseWriter* w) { writer = w; } -SrsFlvStreamWriter::~SrsFlvStreamWriter() +SrsStreamWriter::~SrsStreamWriter() { } -int SrsFlvStreamWriter::open(std::string /*file*/) +int SrsStreamWriter::open(std::string /*file*/) { return ERROR_SUCCESS; } -void SrsFlvStreamWriter::close() +void SrsStreamWriter::close() { } -bool SrsFlvStreamWriter::is_open() +bool SrsStreamWriter::is_open() { return true; } -int64_t SrsFlvStreamWriter::tellg() +int64_t SrsStreamWriter::tellg() { return 0; } -int SrsFlvStreamWriter::write(void* buf, size_t count, ssize_t* pnwrite) +int SrsStreamWriter::write(void* buf, size_t count, ssize_t* pnwrite) { if (pnwrite) { *pnwrite = count; @@ -189,6 +275,20 @@ int SrsLiveStream::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r) { int ret = ERROR_SUCCESS; + bool serve_flv_streaming = false; + bool serve_aac_streaming = false; + + srs_assert(entry); + if (srs_string_ends_with(entry->pattern, ".flv")) { + serve_flv_streaming = true; + } else if (srs_string_ends_with(entry->pattern, ".aac")) { + serve_aac_streaming = true; + } else { + ret = ERROR_HTTP_LIVE_STREAM_EXT; + srs_error("http: unsupported pattern %s", entry->pattern.c_str()); + return ret; + } + // create consumer of souce. SrsConsumer* consumer = NULL; if ((ret = source->create_consumer(consumer)) != ERROR_SUCCESS) { @@ -201,20 +301,25 @@ int SrsLiveStream::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r) SrsMessageArray msgs(SRS_PERF_MW_MSGS); // TODO: FIMXE: add pithy print. - // write http header for ts. + // write http header for streaming. w->header()->set_content_length((int64_t)2 * 1024 * 1024 * 1024); - w->header()->set_content_type("video/x-flv"); + if (serve_flv_streaming) { + w->header()->set_content_type("video/x-flv"); + } + if (serve_aac_streaming) { + w->header()->set_content_type("audio/x-aac"); + } // the memory writer. - SrsFlvStreamWriter writer(w); + SrsStreamWriter writer(w); - SrsFlvEncoder enc; - if ((ret = enc.initialize(&writer)) != ERROR_SUCCESS) { - return ret; + ISrsStreamEncoder* enc = NULL; + if (serve_flv_streaming) { + enc = new SrsFlvStreamEncoder(); } + SrsAutoFree(ISrsStreamEncoder, enc); - // write flv header. - if ((ret = enc.write_header()) != ERROR_SUCCESS) { + if ((ret = enc->initialize(&writer)) != ERROR_SUCCESS) { return ret; } @@ -223,23 +328,23 @@ int SrsLiveStream::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r) // each msg in msgs.msgs must be free, for the SrsMessageArray never free them. int count = 0; if ((ret = consumer->dump_packets(&msgs, count)) != ERROR_SUCCESS) { - srs_error("get messages from consumer failed. ret=%d", ret); + srs_error("http: get messages from consumer failed. ret=%d", ret); return ret; } if (count <= 0) { - srs_info("mw sleep %dms for no msg", mw_sleep); + srs_info("http: mw sleep %dms for no msg", mw_sleep); // directly use sleep, donot use consumer wait. st_usleep(SRS_CONSTS_RTMP_PULSE_TIMEOUT_US); // ignore when nothing got. continue; } - srs_info("got %d msgs, min=%d, mw=%d", count, + srs_info("http: got %d msgs, min=%d, mw=%d", count, SRS_PERF_MW_MIN_MSGS, SRS_CONSTS_RTMP_PULSE_TIMEOUT_US / 1000); // sendout all messages. - ret = send_messages(&enc, msgs.msgs, count); + ret = streaming_send_messages(enc, msgs.msgs, count); // free the messages. for (int i = 0; i < count; i++) { @@ -250,7 +355,7 @@ int SrsLiveStream::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r) // check send error code. if (ret != ERROR_SUCCESS) { if (!srs_is_client_gracefully_close(ret)) { - srs_error("send messages to client failed. ret=%d", ret); + srs_error("http: send messages to client failed. ret=%d", ret); } return ret; } @@ -259,7 +364,7 @@ int SrsLiveStream::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r) return ret; } -int SrsLiveStream::send_messages(SrsFlvEncoder* enc, SrsSharedPtrMessage** msgs, int nb_msgs) +int SrsLiveStream::streaming_send_messages(ISrsStreamEncoder* enc, SrsSharedPtrMessage** msgs, int nb_msgs) { int ret = ERROR_SUCCESS; diff --git a/trunk/src/app/srs_app_http_conn.hpp b/trunk/src/app/srs_app_http_conn.hpp index 1d47df01af..3f90da7522 100644 --- a/trunk/src/app/srs_app_http_conn.hpp +++ b/trunk/src/app/srs_app_http_conn.hpp @@ -41,6 +41,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. class SrsSource; class SrsRequest; class SrsStSocket; +class SrsAacEncoder; class SrsFlvEncoder; class SrsHttpParser; class SrsHttpMessage; @@ -62,16 +63,65 @@ class SrsVodStream : public SrsGoHttpFileServer virtual int serve_flv_stream(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath, int offset); }; +/** +* the stream encoder in some codec, for example, flv or aac. +*/ +class ISrsStreamEncoder +{ +public: + ISrsStreamEncoder(); + virtual ~ISrsStreamEncoder(); +public: + virtual int initialize(SrsFileWriter* w) = 0; + virtual int write_audio(int64_t timestamp, char* data, int size) = 0; + virtual int write_video(int64_t timestamp, char* data, int size) = 0; + virtual int write_metadata(int64_t timestamp, char* data, int size) = 0; +}; + +/** +* the flv stream encoder, remux rtmp stream to flv stream. +*/ +class SrsFlvStreamEncoder : public ISrsStreamEncoder +{ +private: + SrsFlvEncoder* enc; +public: + SrsFlvStreamEncoder(); + virtual ~SrsFlvStreamEncoder(); +public: + virtual int initialize(SrsFileWriter* w); + virtual int write_audio(int64_t timestamp, char* data, int size); + virtual int write_video(int64_t timestamp, char* data, int size); + virtual int write_metadata(int64_t timestamp, char* data, int size); +}; + +/** +* the aac stream encoder, remux rtmp stream to aac stream. +*/ +class SrsAacStreamEncoder : public ISrsStreamEncoder +{ +private: + SrsAacEncoder* enc; +public: + SrsAacStreamEncoder(); + virtual ~SrsAacStreamEncoder(); +public: + virtual int initialize(SrsFileWriter* w); + virtual int write_audio(int64_t timestamp, char* data, int size); + virtual int write_video(int64_t timestamp, char* data, int size); + virtual int write_metadata(int64_t timestamp, char* data, int size); +}; + /** * write stream to http response direclty. */ -class SrsFlvStreamWriter : public SrsFileWriter +class SrsStreamWriter : public SrsFileWriter { private: ISrsGoHttpResponseWriter* writer; public: - SrsFlvStreamWriter(ISrsGoHttpResponseWriter* w); - virtual ~SrsFlvStreamWriter(); + SrsStreamWriter(ISrsGoHttpResponseWriter* w); + virtual ~SrsStreamWriter(); public: virtual int open(std::string file); virtual void close(); @@ -97,7 +147,7 @@ class SrsLiveStream : public ISrsGoHttpHandler public: virtual int serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r); private: - virtual int send_messages(SrsFlvEncoder* enc, SrsSharedPtrMessage** msgs, int nb_msgs); + virtual int streaming_send_messages(ISrsStreamEncoder* enc, SrsSharedPtrMessage** msgs, int nb_msgs); }; /** diff --git a/trunk/src/kernel/srs_kernel_aac.cpp b/trunk/src/kernel/srs_kernel_aac.cpp new file mode 100644 index 0000000000..c2bc4903cc --- /dev/null +++ b/trunk/src/kernel/srs_kernel_aac.cpp @@ -0,0 +1,246 @@ +/* +The MIT License (MIT) + +Copyright (c) 2013-2015 winlin + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include + +// for srs-librtmp, @see https://github.com/winlinvip/simple-rtmp-server/issues/213 +#ifndef _WIN32 +#include +#endif + +#include +#include +using namespace std; + +#include +#include +#include +#include + +#define SRS_FLV_TAG_HEADER_SIZE 11 +#define SRS_FLV_PREVIOUS_TAG_SIZE 4 + +SrsAacEncoder::SrsAacEncoder() +{ + _fs = NULL; + tag_stream = new SrsStream(); +} + +SrsAacEncoder::~SrsAacEncoder() +{ + srs_freep(tag_stream); +} + +int SrsAacEncoder::initialize(SrsFileWriter* fs) +{ + int ret = ERROR_SUCCESS; + + srs_assert(fs); + + if (!fs->is_open()) { + ret = ERROR_KERNEL_FLV_STREAM_CLOSED; + srs_warn("stream is not open for decoder. ret=%d", ret); + return ret; + } + + _fs = fs; + + return ret; +} + +int SrsAacEncoder::write_header() +{ + int ret = ERROR_SUCCESS; + + // 9bytes header and 4bytes first previous-tag-size + static char flv_header[] = { + 'F', 'L', 'V', // Signatures "FLV" + (char)0x01, // File version (for example, 0x01 for FLV version 1) + (char)0x00, // 4, audio; 1, video; 5 audio+video. + (char)0x00, (char)0x00, (char)0x00, (char)0x09 // DataOffset UI32 The length of this header in bytes + }; + + // flv specification should set the audio and video flag, + // actually in practise, application generally ignore this flag, + // so we generally set the audio/video to 0. + + // write 9bytes header. + if ((ret = write_header(flv_header)) != ERROR_SUCCESS) { + return ret; + } + + return ret; +} + +int SrsAacEncoder::write_header(char flv_header[9]) +{ + int ret = ERROR_SUCCESS; + + // write data. + if ((ret = _fs->write(flv_header, 9, NULL)) != ERROR_SUCCESS) { + srs_error("write flv header failed. ret=%d", ret); + return ret; + } + + char pts[] = { (char)0x00, (char)0x00, (char)0x00, (char)0x00 }; + if ((ret = _fs->write(pts, 4, NULL)) != ERROR_SUCCESS) { + return ret; + } + + return ret; +} + +int SrsAacEncoder::write_metadata(char type, char* data, int size) +{ + int ret = ERROR_SUCCESS; + + srs_assert(data); + + // 11 bytes tag header + static char tag_header[] = { + (char)type, // TagType UB [5], 18 = script data + (char)0x00, (char)0x00, (char)0x00, // DataSize UI24 Length of the message. + (char)0x00, (char)0x00, (char)0x00, // Timestamp UI24 Time in milliseconds at which the data in this tag applies. + (char)0x00, // TimestampExtended UI8 + (char)0x00, (char)0x00, (char)0x00, // StreamID UI24 Always 0. + }; + + // write data size. + if ((ret = tag_stream->initialize(tag_header + 1, 3)) != ERROR_SUCCESS) { + return ret; + } + tag_stream->write_3bytes(size); + + if ((ret = write_tag(tag_header, sizeof(tag_header), data, size)) != ERROR_SUCCESS) { + srs_error("write flv data tag failed. ret=%d", ret); + return ret; + } + + return ret; +} + +int SrsAacEncoder::write_audio(int64_t timestamp, char* data, int size) +{ + int ret = ERROR_SUCCESS; + + srs_assert(data); + + timestamp &= 0x7fffffff; + + // 11bytes tag header + static char tag_header[] = { + (char)8, // TagType UB [5], 8 = audio + (char)0x00, (char)0x00, (char)0x00, // DataSize UI24 Length of the message. + (char)0x00, (char)0x00, (char)0x00, // Timestamp UI24 Time in milliseconds at which the data in this tag applies. + (char)0x00, // TimestampExtended UI8 + (char)0x00, (char)0x00, (char)0x00, // StreamID UI24 Always 0. + }; + + // write data size. + if ((ret = tag_stream->initialize(tag_header + 1, 7)) != ERROR_SUCCESS) { + return ret; + } + tag_stream->write_3bytes(size); + tag_stream->write_3bytes((int32_t)timestamp); + // default to little-endian + tag_stream->write_1bytes((timestamp >> 24) & 0xFF); + + if ((ret = write_tag(tag_header, sizeof(tag_header), data, size)) != ERROR_SUCCESS) { + srs_error("write flv audio tag failed. ret=%d", ret); + return ret; + } + + return ret; +} + +int SrsAacEncoder::write_video(int64_t timestamp, char* data, int size) +{ + int ret = ERROR_SUCCESS; + + srs_assert(data); + + timestamp &= 0x7fffffff; + + // 11bytes tag header + static char tag_header[] = { + (char)9, // TagType UB [5], 9 = video + (char)0x00, (char)0x00, (char)0x00, // DataSize UI24 Length of the message. + (char)0x00, (char)0x00, (char)0x00, // Timestamp UI24 Time in milliseconds at which the data in this tag applies. + (char)0x00, // TimestampExtended UI8 + (char)0x00, (char)0x00, (char)0x00, // StreamID UI24 Always 0. + }; + + // write data size. + if ((ret = tag_stream->initialize(tag_header + 1, 7)) != ERROR_SUCCESS) { + return ret; + } + tag_stream->write_3bytes(size); + tag_stream->write_3bytes((int32_t)timestamp); + // default to little-endian + tag_stream->write_1bytes((timestamp >> 24) & 0xFF); + + if ((ret = write_tag(tag_header, sizeof(tag_header), data, size)) != ERROR_SUCCESS) { + srs_error("write flv video tag failed. ret=%d", ret); + return ret; + } + + return ret; +} + +int SrsAacEncoder::size_tag(int data_size) +{ + srs_assert(data_size >= 0); + return SRS_FLV_TAG_HEADER_SIZE + data_size + SRS_FLV_PREVIOUS_TAG_SIZE; +} + +int SrsAacEncoder::write_tag(char* header, int header_size, char* tag, int tag_size) +{ + int ret = ERROR_SUCCESS; + + // write tag header. + if ((ret = _fs->write(header, header_size, NULL)) != ERROR_SUCCESS) { + srs_error("write flv tag header failed. ret=%d", ret); + return ret; + } + + // write tag data. + if ((ret = _fs->write(tag, tag_size, NULL)) != ERROR_SUCCESS) { + srs_error("write flv tag failed. ret=%d", ret); + return ret; + } + + // PreviousTagSizeN UI32 Size of last tag, including its header, in bytes. + static char pre_size[SRS_FLV_PREVIOUS_TAG_SIZE]; + if ((ret = tag_stream->initialize(pre_size, SRS_FLV_PREVIOUS_TAG_SIZE)) != ERROR_SUCCESS) { + return ret; + } + tag_stream->write_4bytes(tag_size + header_size); + if ((ret = _fs->write(pre_size, sizeof(pre_size), NULL)) != ERROR_SUCCESS) { + srs_error("write flv previous tag size failed. ret=%d", ret); + return ret; + } + + return ret; +} + + diff --git a/trunk/src/kernel/srs_kernel_aac.hpp b/trunk/src/kernel/srs_kernel_aac.hpp new file mode 100644 index 0000000000..c0a4347a28 --- /dev/null +++ b/trunk/src/kernel/srs_kernel_aac.hpp @@ -0,0 +1,94 @@ +/* +The MIT License (MIT) + +Copyright (c) 2013-2015 winlin + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef SRS_KERNEL_AAC_HPP +#define SRS_KERNEL_AAC_HPP + +/* +#include +*/ +#include + +#include + +class SrsStream; +class SrsFileWriter; +class SrsFileReader; + +/** +* encode data to flv file. +*/ +class SrsAacEncoder +{ +private: + SrsFileWriter* _fs; +private: + SrsStream* tag_stream; +public: + SrsAacEncoder(); + virtual ~SrsAacEncoder(); +public: + /** + * initialize the underlayer file stream. + * @remark user can initialize multiple times to encode multiple flv files. + * @remark, user must free the fs, flv encoder never close/free it. + */ + virtual int initialize(SrsFileWriter* fs); +public: + /** + * write flv header. + * write following: + * 1. E.2 The FLV header + * 2. PreviousTagSize0 UI32 Always 0 + * that is, 9+4=13bytes. + */ + virtual int write_header(); + virtual int write_header(char flv_header[9]); + /** + * write flv metadata. + * @param type, the type of data, or other message type. + * @param data, the amf0 metadata which serialize from: + * AMF0 string: onMetaData, + * AMF0 object: the metadata object. + * @remark assert data is not NULL. + */ + virtual int write_metadata(char type, char* data, int size); + /** + * write audio/video packet. + * @remark assert data is not NULL. + */ + virtual int write_audio(int64_t timestamp, char* data, int size); + virtual int write_video(int64_t timestamp, char* data, int size); +public: + /** + * get the tag size, + * including the tag header, body, and 4bytes previous tag size. + * @remark assert data_size is not negative. + */ + static int size_tag(int data_size); +private: + virtual int write_tag(char* header, int header_size, char* tag, int tag_size); +}; + +#endif + diff --git a/trunk/src/kernel/srs_kernel_error.hpp b/trunk/src/kernel/srs_kernel_error.hpp index f4b2640e68..7a9054097c 100644 --- a/trunk/src/kernel/srs_kernel_error.hpp +++ b/trunk/src/kernel/srs_kernel_error.hpp @@ -211,6 +211,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define ERROR_HTTP_PATTERN_DUPLICATED 4001 #define ERROR_HTTP_URL_NOT_CLEAN 4002 #define ERROR_HTTP_CONTENT_LENGTH 4003 +#define ERROR_HTTP_LIVE_STREAM_EXT 4004 /** * whether the error code is an system control error. diff --git a/trunk/src/srs/srs.upp b/trunk/src/srs/srs.upp index b267c032a8..2bc0cd37d3 100755 --- a/trunk/src/srs/srs.upp +++ b/trunk/src/srs/srs.upp @@ -18,6 +18,8 @@ file ..\core\srs_core_performance.hpp, ..\core\srs_core_performance.cpp, kernel readonly separator, + ..\kernel\srs_kernel_aac.hpp, + ..\kernel\srs_kernel_aac.cpp, ..\kernel\srs_kernel_codec.hpp, ..\kernel\srs_kernel_codec.cpp, ..\kernel\srs_kernel_consts.hpp,