1
0
Fork 0
mirror of https://github.com/ossrs/srs.git synced 2025-02-14 12:21:55 +00:00

support flv inject and flv http streaming with start=bytes. 0.9.122

This commit is contained in:
winlin 2014-05-29 12:09:26 +08:00
parent d56f445076
commit 7ec202ee41
10 changed files with 241 additions and 29 deletions

View file

@ -231,6 +231,7 @@ Supported operating systems and hardware:
* 2013-10-17, Created.<br/>
## History
* v1.0, 2014-05-29, support flv inject and flv http streaming with start=bytes. 0.9.122
* <strong>v1.0, 2014-05-28, [1.0 mainline4(0.9.120)](https://github.com/winlinvip/simple-rtmp-server/releases/tag/1.0.mainline4) released. 39200 lines.</strong>
* v1.0, 2014-05-27, fix [#87](https://github.com/winlinvip/simple-rtmp-server/issues/87), add source id for full trackable log. 0.9.120
* v1.0, 2014-05-27, fix [#84](https://github.com/winlinvip/simple-rtmp-server/issues/84), unpublish when edge disconnect. 0.9.119

View file

@ -38,7 +38,6 @@ gcc srs_flv_injecter.c ../../objs/lib/srs_librtmp.a -g -O0 -lstdc++ -o srs_flv_i
#define ERROR_INJECTED 10000
int process(const char* in_flv_file, const char* out_flv_file, srs_flv_t* pic, srs_flv_t* poc);
int inject_flv(srs_flv_t ic, srs_flv_t oc);
int main(int argc, char** argv)
{
int ret = 0;
@ -108,22 +107,52 @@ int process(const char* in_flv_file, const char* out_flv_file, srs_flv_t* pic, s
{
int ret = 0;
if ((*pic = srs_flv_open_read(in_flv_file)) == NULL) {
srs_flv_t ic;
srs_flv_t oc;
// to adjust metadata.
// the ic metadata end offset, the next tag start offset.
// all oc metadata must adjust according to:
// adjust = new_metadata_end_offset - metadata_end_offset
int64_t metadata_end_offset = 0;
// metadata
srs_amf0_t amf0_name = NULL;
srs_amf0_t amf0_data = NULL;
srs_amf0_t filepositions = NULL;
if ((ic = srs_flv_open_read(in_flv_file)) == NULL) {
ret = 2;
trace("open input flv file failed. ret=%d", ret);
return ret;
}
*pic = ic;
if ((*poc = srs_flv_open_write(out_flv_file)) == NULL) {
if ((oc = srs_flv_open_write(out_flv_file)) == NULL) {
ret = 2;
trace("open output flv file failed. ret=%d", ret);
return ret;
}
*poc = oc;
if ((ret = inject_flv(*pic, *poc)) != 0) {
/**
* we use two roundtrip to avoid the paddings of metadata,
* to support large keyframes videos without padding fields.
*/
// build keyframes offset to metadata.
if ((ret = build_keyframes(ic, &amf0_name, &amf0_data, &filepositions, &metadata_end_offset)) != 0) {
return ret;
}
// inject the metadata to oc.
if ((ret = do_inject_flv(ic, oc, amf0_name, amf0_data, filepositions, metadata_end_offset)) != 0) {
return ret;
}
// TODO: FIXME: mem leak when error.
srs_amf0_free(amf0_name);
srs_amf0_free(amf0_data);
return ret;
}
@ -148,12 +177,13 @@ int parse_metadata(char* data, int size, srs_amf0_t* pname, srs_amf0_t* pdata)
return ret;
}
int inject_flv(srs_flv_t ic, srs_flv_t oc)
int build_keyframes(srs_flv_t ic, srs_amf0_t *pname, srs_amf0_t* pdata, srs_amf0_t* pfilepositions, int64_t* pmetadata_end_offset)
{
int ret = 0;
// flv header
char header[13];
// packet data
char type;
u_int32_t timestamp = 0;
@ -163,8 +193,8 @@ int inject_flv(srs_flv_t ic, srs_flv_t oc)
// metadata
srs_amf0_t amf0_name = NULL;
int amf0_name_size = 0;
srs_amf0_t amf0_data = NULL;
srs_amf0_t keyframes = NULL;
srs_amf0_t filepositions = NULL;
srs_amf0_t times = NULL;
@ -184,7 +214,7 @@ int inject_flv(srs_flv_t ic, srs_flv_t oc)
if ((ret = srs_flv_read_tag_header(ic, &type, &size, &timestamp)) != 0) {
if (srs_flv_is_eof(ret)) {
trace("parse completed.");
break;
return 0;
}
trace("flv get packet failed. ret=%d", ret);
return ret;
@ -192,7 +222,7 @@ int inject_flv(srs_flv_t ic, srs_flv_t oc)
if (size <= 0) {
trace("invalid size=%d", size);
break;
return ret;
}
// TODO: FIXME: mem leak when error.
@ -208,30 +238,40 @@ int inject_flv(srs_flv_t ic, srs_flv_t oc)
srs_amf0_strict_array_append(times, srs_amf0_create_number(((double)timestamp)/ 1000));
}
} else if (type == SRS_RTMP_TYPE_SCRIPT) {
*pmetadata_end_offset = srs_flv_tellg(ic);
if ((ret = parse_metadata(data, size, &amf0_name, &amf0_data)) != 0) {
return ret;
}
*pname = amf0_name;
*pdata = amf0_data;
if (srs_amf0_is_object(amf0_data)) {
keyframes = srs_amf0_object_property(amf0_data, "keyframes");
if (keyframes != NULL) {
return 0;
if (keyframes == NULL) {
keyframes = srs_amf0_create_ecma_array();
}
keyframes = srs_amf0_create_ecma_array();
srs_amf0_object_property_set(amf0_data, "keyframes", keyframes);
filepositions = srs_amf0_create_strict_array();
// always clear the old keyframes.
srs_amf0_ecma_array_clear(keyframes);
*pfilepositions = filepositions = srs_amf0_create_strict_array();
srs_amf0_object_property_set(keyframes, "filepositions", filepositions);
times = srs_amf0_create_strict_array();
srs_amf0_object_property_set(keyframes, "times", times);
} else if (srs_amf0_is_ecma_array(amf0_data)) {
keyframes = srs_amf0_ecma_array_property(amf0_data, "keyframes");
if (keyframes != NULL) {
return 0;
if (keyframes == NULL) {
keyframes = srs_amf0_create_ecma_array();
}
keyframes = srs_amf0_create_ecma_array();
srs_amf0_ecma_array_property_set(amf0_data, "keyframes", keyframes);
filepositions = srs_amf0_create_strict_array();
// always clear the old keyframes.
srs_amf0_ecma_array_clear(keyframes);
*pfilepositions = filepositions = srs_amf0_create_strict_array();
srs_amf0_ecma_array_property_set(keyframes, "filepositions", filepositions);
times = srs_amf0_create_strict_array();
srs_amf0_ecma_array_property_set(keyframes, "times", times);
}
@ -240,6 +280,30 @@ int inject_flv(srs_flv_t ic, srs_flv_t oc)
free(data);
}
return ret;
}
int do_inject_flv(srs_flv_t ic, srs_flv_t oc, srs_amf0_t amf0_name, srs_amf0_t amf0_data, srs_amf0_t filepositions, int64_t metadata_end_offset)
{
int ret = 0;
// flv header
char header[13];
// packet data
char type;
u_int32_t timestamp = 0;
char* data = NULL;
int32_t size;
// metadata
srs_amf0_t fileposition = NULL;
int amf0_name_size = 0;
int i;
// the metadata end offset, the next tag start offset.
int64_t new_metadata_end_offset = 0;
int offset_adjust = 0;
// reset to write injected file
srs_flv_lseek(ic, 0);
@ -255,7 +319,18 @@ int inject_flv(srs_flv_t ic, srs_flv_t oc)
if (amf0_name != NULL && amf0_data != NULL) {
amf0_name_size = srs_amf0_size(amf0_name);
size = amf0_name_size + srs_amf0_size(amf0_data);
// adjust all offset of keyframes.
new_metadata_end_offset = srs_flv_tellg(oc) + srs_flv_size_tag(size);
// the adjust is new offset sub the old offset of metadata end.
offset_adjust = new_metadata_end_offset - metadata_end_offset;
for (i = 0; i < srs_amf0_strict_array_property_count(filepositions); i++) {
fileposition = srs_amf0_strict_array_property_at(filepositions, i);
srs_amf0_set_number(fileposition, srs_amf0_to_number(fileposition) + offset_adjust);
}
data = (char*)malloc(size);
memset(data, 0, size);
if ((ret = srs_amf0_serialize(amf0_name, data, amf0_name_size)) != 0) {
return ret;
}
@ -267,6 +342,7 @@ int inject_flv(srs_flv_t ic, srs_flv_t oc)
}
free(data);
}
trace("build keyframe infos from flv");
for (;;) {
// tag header
@ -303,8 +379,5 @@ int inject_flv(srs_flv_t ic, srs_flv_t oc)
free(data);
}
srs_amf0_free(amf0_name);
srs_amf0_free(amf0_data);
return ret;
}

View file

@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// current release version
#define VERSION_MAJOR "0"
#define VERSION_MINOR "9"
#define VERSION_REVISION "121"
#define VERSION_REVISION "122"
#define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION
// server info.
#define RTMP_SIG_SRS_KEY "SRS"

View file

@ -330,6 +330,11 @@ int SrsFlvEncoder::write_video(int64_t timestamp, char* data, int size)
return ret;
}
int SrsFlvEncoder::size_tag(int data_size)
{
return SRS_FLV_TAG_HEADER_SIZE + data_size + SRS_FLV_PREVIOUS_TAG_SIZE;
}
int SrsFlvEncoder::write_tag(char* header, int header_size, char* tag, int tag_size)
{
int ret = ERROR_SUCCESS;

View file

@ -105,6 +105,11 @@ public:
*/
virtual int write_audio(int64_t timestamp, char* data, int size);
virtual int write_video(int64_t timestamp, char* data, int size);
/**
* get the tag size,
* including the tag header, body, and 4bytes previous tag size.
*/
static int size_tag(int data_size);
private:
virtual int write_tag(char* header, int header_size, char* tag, int tag_size);
};

View file

@ -519,6 +519,11 @@ int srs_flv_write_tag(srs_flv_t flv, char type, int32_t time, char* data, int si
return ret;
}
int srs_flv_size_tag(int data_size)
{
return SrsFlvEncoder::size_tag(data_size);
}
int64_t srs_flv_tellg(srs_flv_t flv)
{
FlvContext* context = (FlvContext*)flv;
@ -684,6 +689,12 @@ amf0_number srs_amf0_to_number(srs_amf0_t amf0)
return any->to_number();
}
void srs_amf0_set_number(srs_amf0_t amf0, amf0_number value)
{
SrsAmf0Any* any = (SrsAmf0Any*)amf0;
any->set_number(value);
}
int srs_amf0_object_property_count(srs_amf0_t amf0)
{
SrsAmf0Object* obj = (SrsAmf0Object*)amf0;
@ -746,6 +757,12 @@ void srs_amf0_ecma_array_property_set(srs_amf0_t amf0, const char* name, srs_amf
obj->set(name, any);
}
void srs_amf0_ecma_array_clear(srs_amf0_t amf0)
{
SrsAmf0EcmaArray* obj = (SrsAmf0EcmaArray*)amf0;
obj->clear();
}
int srs_amf0_strict_array_property_count(srs_amf0_t amf0)
{
SrsAmf0StrictArray * obj = (SrsAmf0StrictArray*)amf0;

View file

@ -169,6 +169,8 @@ int srs_flv_read_tag_data(srs_flv_t flv, char* data, int32_t size);
int srs_flv_write_header(srs_flv_t flv, char header[9]);
/* write flv tag to file, auto write the 4bytes previous tag size */
int srs_flv_write_tag(srs_flv_t flv, char type, int32_t time, char* data, int size);
/* get the tag size, for flv injecter to adjust offset, size=tag_header+data+previous_tag */
int srs_flv_size_tag(int data_size);
/* file stream */
/* file stream tellg to get offset */
int64_t srs_flv_tellg(srs_flv_t flv);
@ -211,6 +213,8 @@ amf0_bool srs_amf0_is_strict_array(srs_amf0_t amf0);
const char* srs_amf0_to_string(srs_amf0_t amf0);
amf0_bool srs_amf0_to_boolean(srs_amf0_t amf0);
amf0_number srs_amf0_to_number(srs_amf0_t amf0);
/* value setter */
void srs_amf0_set_number(srs_amf0_t amf0, amf0_number value);
/* object value converter */
int srs_amf0_object_property_count(srs_amf0_t amf0);
const char* srs_amf0_object_property_name_at(srs_amf0_t amf0, int index);
@ -223,6 +227,7 @@ const char* srs_amf0_ecma_array_property_name_at(srs_amf0_t amf0, int index);
srs_amf0_t srs_amf0_ecma_array_property_value_at(srs_amf0_t amf0, int index);
srs_amf0_t srs_amf0_ecma_array_property(srs_amf0_t amf0, const char* name);
void srs_amf0_ecma_array_property_set(srs_amf0_t amf0, const char* name, srs_amf0_t value);
void srs_amf0_ecma_array_clear(srs_amf0_t amf0);
/* strict array value converter */
int srs_amf0_strict_array_property_count(srs_amf0_t amf0);
srs_amf0_t srs_amf0_strict_array_property_at(srs_amf0_t amf0, int index);

View file

@ -75,6 +75,7 @@ public:
virtual int total_size();
virtual int read(SrsStream* stream);
virtual int write(SrsStream* stream);
virtual SrsAmf0Any* copy();
};
/**
@ -95,6 +96,7 @@ public:
virtual int total_size();
virtual int read(SrsStream* stream);
virtual int write(SrsStream* stream);
virtual SrsAmf0Any* copy();
};
/**
@ -114,6 +116,7 @@ public:
virtual int total_size();
virtual int read(SrsStream* stream);
virtual int write(SrsStream* stream);
virtual SrsAmf0Any* copy();
};
/**
@ -130,6 +133,7 @@ public:
virtual int total_size();
virtual int read(SrsStream* stream);
virtual int write(SrsStream* stream);
virtual SrsAmf0Any* copy();
};
/**
@ -146,6 +150,7 @@ public:
virtual int total_size();
virtual int read(SrsStream* stream);
virtual int write(SrsStream* stream);
virtual SrsAmf0Any* copy();
};
/**
@ -173,6 +178,8 @@ public:
virtual SrsAmf0Any* get_property(std::string name);
virtual SrsAmf0Any* ensure_property_string(std::string name);
virtual SrsAmf0Any* ensure_property_number(std::string name);
virtual void copy(__SrsUnSortedHashtable* src);
};
/**
@ -191,6 +198,7 @@ public:
virtual int total_size();
virtual int read(SrsStream* stream);
virtual int write(SrsStream* stream);
virtual SrsAmf0Any* copy();
};
/**
@ -310,6 +318,13 @@ SrsAmf0StrictArray* SrsAmf0Any::to_strict_array()
return p;
}
void SrsAmf0Any::set_number(double value)
{
__SrsAmf0Number* p = dynamic_cast<__SrsAmf0Number*>(this);
srs_assert(p != NULL);
p->value = value;
}
bool SrsAmf0Any::is_object_eof()
{
return marker == RTMP_AMF0_ObjectEnd;
@ -433,13 +448,7 @@ __SrsUnSortedHashtable::__SrsUnSortedHashtable()
__SrsUnSortedHashtable::~__SrsUnSortedHashtable()
{
std::vector<SrsAmf0ObjectPropertyType>::iterator it;
for (it = properties.begin(); it != properties.end(); ++it) {
SrsAmf0ObjectPropertyType& elem = *it;
SrsAmf0Any* any = elem.second;
srs_freep(any);
}
properties.clear();
clear();
}
int __SrsUnSortedHashtable::count()
@ -449,6 +458,12 @@ int __SrsUnSortedHashtable::count()
void __SrsUnSortedHashtable::clear()
{
std::vector<SrsAmf0ObjectPropertyType>::iterator it;
for (it = properties.begin(); it != properties.end(); ++it) {
SrsAmf0ObjectPropertyType& elem = *it;
SrsAmf0Any* any = elem.second;
srs_freep(any);
}
properties.clear();
}
@ -543,6 +558,17 @@ SrsAmf0Any* __SrsUnSortedHashtable::ensure_property_number(string name)
return prop;
}
void __SrsUnSortedHashtable::copy(__SrsUnSortedHashtable* src)
{
std::vector<SrsAmf0ObjectPropertyType>::iterator it;
for (it = src->properties.begin(); it != src->properties.end(); ++it) {
SrsAmf0ObjectPropertyType& elem = *it;
std::string key = elem.first;
SrsAmf0Any* any = elem.second;
set(key, any->copy());
}
}
__SrsAmf0ObjectEOF::__SrsAmf0ObjectEOF()
{
marker = RTMP_AMF0_ObjectEnd;
@ -623,6 +649,11 @@ int __SrsAmf0ObjectEOF::write(SrsStream* stream)
return ret;
}
SrsAmf0Any* __SrsAmf0ObjectEOF::copy()
{
return new __SrsAmf0ObjectEOF();
}
SrsAmf0Object::SrsAmf0Object()
{
properties = new __SrsUnSortedHashtable();
@ -750,6 +781,13 @@ int SrsAmf0Object::write(SrsStream* stream)
return ret;
}
SrsAmf0Any* SrsAmf0Object::copy()
{
SrsAmf0Object* copy = new SrsAmf0Object();
copy->properties->copy(properties);
return copy;
}
int SrsAmf0Object::count()
{
return properties->count();
@ -792,6 +830,7 @@ SrsAmf0Any* SrsAmf0Object::ensure_property_number(string name)
SrsAmf0EcmaArray::SrsAmf0EcmaArray()
{
_count = 0;
properties = new __SrsUnSortedHashtable();
eof = new __SrsAmf0ObjectEOF();
marker = RTMP_AMF0_EcmaArray;
@ -937,6 +976,14 @@ int SrsAmf0EcmaArray::write(SrsStream* stream)
return ret;
}
SrsAmf0Any* SrsAmf0EcmaArray::copy()
{
SrsAmf0EcmaArray* copy = new SrsAmf0EcmaArray();
copy->properties->copy(properties);
copy->_count = _count;
return copy;
}
void SrsAmf0EcmaArray::clear()
{
properties->clear();
@ -1097,6 +1144,20 @@ int SrsAmf0StrictArray::write(SrsStream* stream)
return ret;
}
SrsAmf0Any* SrsAmf0StrictArray::copy()
{
SrsAmf0StrictArray* copy = new SrsAmf0StrictArray();
std::vector<SrsAmf0Any*>::iterator it;
for (it = properties.begin(); it != properties.end(); ++it) {
SrsAmf0Any* any = *it;
copy->append(any->copy());
}
copy->_count = _count;
return copy;
}
void SrsAmf0StrictArray::clear()
{
properties.clear();
@ -1116,6 +1177,7 @@ SrsAmf0Any* SrsAmf0StrictArray::at(int index)
void SrsAmf0StrictArray::append(SrsAmf0Any* any)
{
properties.push_back(any);
_count = (int32_t)properties.size();
}
int SrsAmf0Size::utf8(string value)
@ -1216,6 +1278,12 @@ int __SrsAmf0String::write(SrsStream* stream)
return srs_amf0_write_string(stream, value);
}
SrsAmf0Any* __SrsAmf0String::copy()
{
__SrsAmf0String* copy = new __SrsAmf0String(value.c_str());
return copy;
}
__SrsAmf0Boolean::__SrsAmf0Boolean(bool _value)
{
marker = RTMP_AMF0_Boolean;
@ -1241,6 +1309,12 @@ int __SrsAmf0Boolean::write(SrsStream* stream)
return srs_amf0_write_boolean(stream, value);
}
SrsAmf0Any* __SrsAmf0Boolean::copy()
{
__SrsAmf0Boolean* copy = new __SrsAmf0Boolean(value);
return copy;
}
__SrsAmf0Number::__SrsAmf0Number(double _value)
{
marker = RTMP_AMF0_Number;
@ -1266,6 +1340,12 @@ int __SrsAmf0Number::write(SrsStream* stream)
return srs_amf0_write_number(stream, value);
}
SrsAmf0Any* __SrsAmf0Number::copy()
{
__SrsAmf0Number* copy = new __SrsAmf0Number(value);
return copy;
}
__SrsAmf0Null::__SrsAmf0Null()
{
marker = RTMP_AMF0_Null;
@ -1290,6 +1370,12 @@ int __SrsAmf0Null::write(SrsStream* stream)
return srs_amf0_write_null(stream);
}
SrsAmf0Any* __SrsAmf0Null::copy()
{
__SrsAmf0Null* copy = new __SrsAmf0Null();
return copy;
}
__SrsAmf0Undefined::__SrsAmf0Undefined()
{
marker = RTMP_AMF0_Undefined;
@ -1314,6 +1400,12 @@ int __SrsAmf0Undefined::write(SrsStream* stream)
return srs_amf0_write_undefined(stream);
}
SrsAmf0Any* __SrsAmf0Undefined::copy()
{
__SrsAmf0Undefined* copy = new __SrsAmf0Undefined();
return copy;
}
int srs_amf0_read_any(SrsStream* stream, SrsAmf0Any** ppvalue)
{
int ret = ERROR_SUCCESS;

View file

@ -63,6 +63,11 @@ class __SrsAmf0ObjectEOF;
// SrsAmf0Object* obj = SrsAmf0Any::object();
// 5. SrsAmf0EcmaArray: create the amf0 ecma array.
// SrsAmf0EcmaArray* arr = SrsAmf0Any::ecma_array();
// 6. SrsAmf0Any: set basic type value
// SrsAmf0Any* pany = ...
// if (pany->is_number()) {
// pany->set_number(100.1);
// }
//
// please carefully the size and count of amf0 any:
// 1. total_size(): the total memory size the object wrote to buffer.
@ -129,6 +134,12 @@ public:
*/
virtual SrsAmf0EcmaArray* to_ecma_array();
virtual SrsAmf0StrictArray* to_strict_array();
public:
/**
* set the number of any when is_number() indicates true.
* user must ensure the type is a number, or assert failed.
*/
virtual void set_number(double value);
public:
/**
* get the size of amf0 any, including the marker size.
@ -139,6 +150,7 @@ public:
*/
virtual int read(SrsStream* stream) = 0;
virtual int write(SrsStream* stream) = 0;
virtual SrsAmf0Any* copy() = 0;
public:
static SrsAmf0Any* str(const char* value = NULL);
static SrsAmf0Any* boolean(bool value = false);
@ -175,6 +187,7 @@ public:
virtual int total_size();
virtual int read(SrsStream* stream);
virtual int write(SrsStream* stream);
virtual SrsAmf0Any* copy();
public:
virtual int count();
@ -215,6 +228,7 @@ public:
virtual int total_size();
virtual int read(SrsStream* stream);
virtual int write(SrsStream* stream);
virtual SrsAmf0Any* copy();
public:
virtual void clear();
@ -254,6 +268,7 @@ public:
virtual int total_size();
virtual int read(SrsStream* stream);
virtual int write(SrsStream* stream);
virtual SrsAmf0Any* copy();
public:
virtual void clear();

View file

@ -3173,10 +3173,9 @@ int SrsOnMetaDataPacket::decode(SrsStream* stream)
// if ecma array, copy to object.
for (int i = 0; i < arr->count(); i++) {
metadata->set(arr->key_at(i), arr->value_at(i));
metadata->set(arr->key_at(i), arr->value_at(i)->copy());
}
arr->clear();
srs_info("decode metadata array success");
}