diff --git a/trunk/research/librtmp/srs_flv_codec.h b/trunk/research/librtmp/srs_flv_codec.h deleted file mode 100644 index 838df5034..000000000 --- a/trunk/research/librtmp/srs_flv_codec.h +++ /dev/null @@ -1,147 +0,0 @@ -/* -The MIT License (MIT) - -Copyright (c) 2013-2014 winlin - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#ifndef SRS_RESEARH_FLV_CODEC_HPP -#define SRS_RESEARH_FLV_CODEC_HPP - -/* -#include "srs_flv_codec.h" -*/ - -#include -#include -#include -#include - -#define ERROR_FLV_CODEC_EOF 100 - -int open_flv_file(char* in_flv_file) -{ - return open(in_flv_file, O_RDONLY); -} - -void close_flv_file(int fd) -{ - if (fd > 0) { - close(fd); - } -} - -int flv_open_ic(int flv_fd) -{ - int ret = 0; - - char h[13]; // 9+4 - - if (read(flv_fd, h, sizeof(h)) != sizeof(h)) { - ret = -1; - trace("read flv header failed. ret=%d", ret); - return ret; - } - - if (h[0] != 'F' || h[1] != 'L' || h[2] != 'V') { - ret = -1; - trace("input is not a flv file. ret=%d", ret); - return ret; - } - - return ret; -} - -int flv_read_packet(int flv_fd, int* type, u_int32_t* timestamp, char** data, int* size) -{ - int ret = 0; - - char th[11]; // tag header - char ts[4]; // tag size - - int32_t data_size = 0; - u_int32_t time = 0; - - char* pp; - - // read tag header - if ((ret = read(flv_fd, th, sizeof(th))) != sizeof(th)) { - if (ret == 0) { - return ERROR_FLV_CODEC_EOF; - } - ret = -1; - trace("read flv tag header failed. ret=%d", ret); - return ret; - } - - // Reserved UB [2] - // Filter UB [1] - // TagType UB [5] - *type = (int)(th[0] & 0x1F); - - // DataSize UI24 - pp = (char*)&data_size; - pp[2] = th[1]; - pp[1] = th[2]; - pp[0] = th[3]; - - // Timestamp UI24 - pp = (char*)&time; - pp[2] = th[4]; - pp[1] = th[5]; - pp[0] = th[6]; - - // TimestampExtended UI8 - pp[3] = th[7]; - - *timestamp = time; - - // check data size. - if (data_size <= 0) { - ret = -1; - trace("invalid data size. size=%d, ret=%d", data_size, ret); - return ret; - } - - // read tag data. - *size = data_size; - *data = (char*)malloc(data_size); - if ((ret = read(flv_fd, *data, data_size)) != data_size) { - if (ret == 0) { - return ERROR_FLV_CODEC_EOF; - } - ret = -1; - trace("read flv tag data failed. size=%d, ret=%d", data_size, ret); - return ret; - } - - // ignore 4bytes tag size. - if ((ret = read(flv_fd, ts, sizeof(ts))) != sizeof(ts)) { - if (ret == 0) { - return ERROR_FLV_CODEC_EOF; - } - ret = -1; - trace("read flv tag size failed. ret=%d", ret); - return ret; - } - - return 0; -} - -#endif diff --git a/trunk/research/librtmp/srs_flv_injecter.c b/trunk/research/librtmp/srs_flv_injecter.c index 445869f92..8a500b445 100644 --- a/trunk/research/librtmp/srs_flv_injecter.c +++ b/trunk/research/librtmp/srs_flv_injecter.c @@ -34,7 +34,8 @@ gcc srs_flv_injecter.c ../../objs/lib/srs_librtmp.a -g -O0 -lstdc++ -o srs_flv_i #include "../../objs/include/srs_librtmp.h" #include "srs_research_public.h" -#include "srs_flv_codec.h" + +#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); @@ -87,7 +88,12 @@ int main(int argc, char** argv) if (ret != 0) { unlink(tmp_file); - trace("error, remove tmp file."); + if (ret == ERROR_INJECTED) { + ret = 0; + trace("file already injected."); + } else { + trace("error, remove tmp file."); + } } else { rename(tmp_file, out_flv_file); trace("completed, rename to %s", out_flv_file); @@ -153,22 +159,118 @@ int inject_flv(srs_flv_t ic, srs_flv_t oc) u_int32_t timestamp = 0; char* data = NULL; int32_t size; + int64_t offset = 0; // 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; // reset to generate metadata srs_flv_lseek(ic, 0); - if ((ret = srs_flv_read_header(oc, header)) != 0) { + if ((ret = srs_flv_read_header(ic, header)) != 0) { return ret; } - trace("start inject flv"); + trace("build keyframe infos from flv"); + for (;;) { + offset = srs_flv_tellg(ic); + + // tag header + if ((ret = srs_flv_read_tag_header(ic, &type, &size, ×tamp)) != 0) { + if (srs_flv_is_eof(ret)) { + trace("parse completed."); + break; + } + trace("flv get packet failed. ret=%d", ret); + return ret; + } + + if (size <= 0) { + trace("invalid size=%d", size); + break; + } + + // TODO: FIXME: mem leak when error. + data = (char*)malloc(size); + if ((ret = srs_flv_read_tag_data(ic, data, size)) != 0) { + return ret; + } + + // data tag + if (type == SRS_RTMP_TYPE_VIDEO) { + if (!srs_flv_is_sequence_header(data, size) && srs_flv_is_keyframe(data, size)) { + srs_amf0_strict_array_append(filepositions, srs_amf0_create_number(offset)); + srs_amf0_strict_array_append(times, srs_amf0_create_number(((double)timestamp)/ 1000)); + } + } else if (type == SRS_RTMP_TYPE_SCRIPT) { + if ((ret = parse_metadata(data, size, &amf0_name, &amf0_data)) != 0) { + return ret; + } + + if (srs_amf0_is_object(amf0_data)) { + keyframes = srs_amf0_object_property(amf0_data, "keyframes"); + if (keyframes != NULL) { + return 0; + } + keyframes = srs_amf0_create_ecma_array(); + srs_amf0_object_property_set(amf0_data, "keyframes", keyframes); + 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; + } + keyframes = srs_amf0_create_ecma_array(); + srs_amf0_ecma_array_property_set(amf0_data, "keyframes", keyframes); + 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); + } + } + + free(data); + } + + // reset to write injected file + srs_flv_lseek(ic, 0); + + if ((ret = srs_flv_read_header(ic, header)) != 0) { + return ret; + } + + if ((ret = srs_flv_write_header(oc, header)) != 0) { + return ret; + } + + // write metadata + if (amf0_name != NULL && amf0_data != NULL) { + amf0_name_size = srs_amf0_size(amf0_name); + size = amf0_name_size + srs_amf0_size(amf0_data); + data = (char*)malloc(size); + if ((ret = srs_amf0_serialize(amf0_name, data, amf0_name_size)) != 0) { + return ret; + } + if ((ret = srs_amf0_serialize(amf0_data, data + amf0_name_size, size - amf0_name_size)) != 0) { + return ret; + } + if ((ret = srs_flv_write_tag(oc, SRS_RTMP_TYPE_SCRIPT, 0, data, size)) != 0) { + return ret; + } + free(data); + } + trace("build keyframe infos from flv"); for (;;) { // tag header - if ((ret = srs_flv_read_tag_header(oc, &type, &size, ×tamp)) != 0) { + if ((ret = srs_flv_read_tag_header(ic, &type, &size, ×tamp)) != 0) { if (srs_flv_is_eof(ret)) { trace("parse completed."); return 0; @@ -184,16 +286,18 @@ int inject_flv(srs_flv_t ic, srs_flv_t oc) // TODO: FIXME: mem leak when error. data = (char*)malloc(size); - if ((ret = srs_flv_read_tag_data(oc, data, size)) != 0) { + if ((ret = srs_flv_read_tag_data(ic, data, size)) != 0) { return ret; } // data tag - if (type == SRS_RTMP_TYPE_VIDEO) { - } else if (type == SRS_RTMP_TYPE_SCRIPT) { - if ((ret = parse_metadata(data, size, &amf0_name, &amf0_data)) != 0) { - return ret; - } + if (type == SRS_RTMP_TYPE_SCRIPT) { + continue; + } + + // copy + if ((ret = srs_flv_write_tag(oc, type, timestamp, data, size)) != 0) { + return ret; } free(data); diff --git a/trunk/research/librtmp/srs_flv_parser.c b/trunk/research/librtmp/srs_flv_parser.c index fd8c2de97..108a483ac 100644 --- a/trunk/research/librtmp/srs_flv_parser.c +++ b/trunk/research/librtmp/srs_flv_parser.c @@ -34,7 +34,6 @@ gcc srs_ingest_flv.c ../../objs/lib/srs_librtmp.a -g -O0 -lstdc++ -o srs_ingest_ #include "../../objs/include/srs_librtmp.h" #include "srs_research_public.h" -#include "srs_flv_codec.h" int parse_flv(srs_flv_t flv); int main(int argc, char** argv) diff --git a/trunk/research/librtmp/srs_ingest_flv.c b/trunk/research/librtmp/srs_ingest_flv.c index ab3e87838..8c4c0a07e 100644 --- a/trunk/research/librtmp/srs_ingest_flv.c +++ b/trunk/research/librtmp/srs_ingest_flv.c @@ -34,9 +34,8 @@ gcc srs_ingest_flv.c ../../objs/lib/srs_librtmp.a -g -O0 -lstdc++ -o srs_ingest_ #include "../../objs/include/srs_librtmp.h" #include "srs_research_public.h" -#include "srs_flv_codec.h" -int proxy(int flv_fd, srs_rtmp_t ortmp); +int proxy(srs_flv_t flv, srs_rtmp_t ortmp); int connect_oc(srs_rtmp_t ortmp); #define RE_PULSE_MS 300 @@ -59,7 +58,7 @@ int main(int argc, char** argv) // rtmp handler srs_rtmp_t ortmp; // flv handler - int flv_fd; + srs_flv_t flv; if (argc <= 2) { printf("ingest flv file and publish to RTMP server\n" @@ -94,8 +93,7 @@ int main(int argc, char** argv) trace("input: %s", in_flv_file); trace("output: %s", out_rtmp_url); - flv_fd = open_flv_file(in_flv_file); - if (flv_fd <= 0) { + if ((flv = srs_flv_open_read(in_flv_file)) == NULL) { ret = 2; trace("open flv file failed. ret=%d", ret); return ret; @@ -103,31 +101,46 @@ int main(int argc, char** argv) ortmp = srs_rtmp_create(out_rtmp_url); - ret = proxy(flv_fd, ortmp); + ret = proxy(flv, ortmp); trace("ingest flv to RTMP completed"); srs_rtmp_destroy(ortmp); - close_flv_file(flv_fd); + srs_flv_close(flv); return ret; } -int do_proxy(int flv_fd, srs_rtmp_t ortmp, int64_t re, u_int32_t* ptimestamp) +int do_proxy(srs_flv_t flv, srs_rtmp_t ortmp, int64_t re, u_int32_t* ptimestamp) { int ret = 0; // packet data - int type, size; + char type; + int size; char* data = NULL; trace("start ingest flv to RTMP stream"); for (;;) { - if ((ret = flv_read_packet(flv_fd, &type, ptimestamp, &data, &size)) != 0) { - trace("irtmp get packet failed. ret=%d", ret); + // tag header + if ((ret = srs_flv_read_tag_header(flv, &type, &size, ptimestamp)) != 0) { + if (srs_flv_is_eof(ret)) { + trace("parse completed."); + return 0; + } + trace("flv get packet failed. ret=%d", ret); + return ret; + } + + if (size <= 0) { + trace("invalid size=%d", size); + break; + } + + // TODO: FIXME: mem leak when error. + data = (char*)malloc(size); + if ((ret = srs_flv_read_tag_data(flv, data, size)) != 0) { return ret; } - verbose("irtmp got packet: type=%s, time=%d, size=%d", - srs_type2string(type), timestamp, size); if ((ret = srs_write_packet(ortmp, type, *ptimestamp, data, size)) != 0) { trace("irtmp get packet failed. ret=%d", ret); @@ -142,12 +155,13 @@ int do_proxy(int flv_fd, srs_rtmp_t ortmp, int64_t re, u_int32_t* ptimestamp) return ret; } -int proxy(int flv_fd, srs_rtmp_t ortmp) +int proxy(srs_flv_t flv, srs_rtmp_t ortmp) { int ret = 0; u_int32_t timestamp = 0; - if ((ret = flv_open_ic(flv_fd)) != 0) { + char header[13]; + if ((ret = srs_flv_read_header(flv, header)) != 0) { return ret; } if ((ret = connect_oc(ortmp)) != 0) { @@ -156,7 +170,7 @@ int proxy(int flv_fd, srs_rtmp_t ortmp) int64_t re = re_create(); - ret = do_proxy(flv_fd, ortmp, re, ×tamp); + ret = do_proxy(flv, ortmp, re, ×tamp); // for the last pulse, always sleep. re_cleanup(re, timestamp); diff --git a/trunk/src/kernel/srs_kernel_flv.cpp b/trunk/src/kernel/srs_kernel_flv.cpp index 55501f2a2..60c7e313f 100644 --- a/trunk/src/kernel/srs_kernel_flv.cpp +++ b/trunk/src/kernel/srs_kernel_flv.cpp @@ -207,20 +207,36 @@ int SrsFlvEncoder::write_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 - (char)0x00, (char)0x00, (char)0x00, (char)0x00// PreviousTagSize0 UI32 Always 0 + (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 SrsFlvEncoder::write_header(char flv_header[9]) +{ + int ret = ERROR_SUCCESS; + // write data. - if ((ret = _fs->write(flv_header, sizeof(flv_header), NULL)) != ERROR_SUCCESS) { + if ((ret = _fs->write(flv_header, 9, NULL)) != ERROR_SUCCESS) { srs_error("write flv header failed. ret=%d", ret); return ret; } + char pts[] = { 0x00, 0x00, 0x00, 0x00 }; + if ((ret = _fs->write(pts, 4, NULL)) != ERROR_SUCCESS) { + return ret; + } + return ret; } diff --git a/trunk/src/kernel/srs_kernel_flv.hpp b/trunk/src/kernel/srs_kernel_flv.hpp index b25680352..8efd3b800 100644 --- a/trunk/src/kernel/srs_kernel_flv.hpp +++ b/trunk/src/kernel/srs_kernel_flv.hpp @@ -92,6 +92,7 @@ public: * that is, 9+4=13bytes. */ virtual int write_header(); + virtual int write_header(char flv_header[9]); /** * write flv metadata. * serialize from: diff --git a/trunk/src/libs/srs_librtmp.cpp b/trunk/src/libs/srs_librtmp.cpp index 3f87879d7..7648d1f70 100644 --- a/trunk/src/libs/srs_librtmp.cpp +++ b/trunk/src/libs/srs_librtmp.cpp @@ -491,6 +491,34 @@ int srs_flv_read_tag_data(srs_flv_t flv, char* data, int32_t size) return ret; } +int srs_flv_write_header(srs_flv_t flv, char header[9]) +{ + int ret = ERROR_SUCCESS; + + FlvContext* context = (FlvContext*)flv; + if ((ret = context->enc.write_header(header)) != ERROR_SUCCESS) { + return ret; + } + + return ret; +} + +int srs_flv_write_tag(srs_flv_t flv, char type, int32_t time, char* data, int size) +{ + int ret = ERROR_SUCCESS; + + FlvContext* context = (FlvContext*)flv; + if (type == SRS_RTMP_TYPE_AUDIO) { + return context->enc.write_audio(time, data, size); + } else if (type == SRS_RTMP_TYPE_VIDEO) { + return context->enc.write_video(time, data, size); + } else { + return context->enc.write_metadata(data, size); + } + + return ret; +} + int64_t srs_flv_tellg(srs_flv_t flv) { FlvContext* context = (FlvContext*)flv; @@ -508,6 +536,16 @@ flv_bool srs_flv_is_eof(int error_code) return error_code == ERROR_SYSTEM_FILE_EOF; } +flv_bool srs_flv_is_sequence_header(char* data, int32_t size) +{ + return SrsCodec::video_is_sequence_header((int8_t*)data, (int)size); +} + +flv_bool srs_flv_is_keyframe(char* data, int32_t size) +{ + return SrsCodec::video_is_keyframe((int8_t*)data, (int)size); +} + srs_amf0_t srs_amf0_parse(char* data, int size, int* nparsed) { int ret = ERROR_SUCCESS; @@ -536,6 +574,21 @@ srs_amf0_t srs_amf0_parse(char* data, int size, int* nparsed) return amf0; } +srs_amf0_t srs_amf0_create_number(amf0_number value) +{ + return SrsAmf0Any::number(value); +} + +srs_amf0_t srs_amf0_create_ecma_array() +{ + return SrsAmf0Any::ecma_array(); +} + +srs_amf0_t srs_amf0_create_strict_array() +{ + return SrsAmf0Any::strict_array(); +} + void srs_amf0_free(srs_amf0_t amf0) { SrsAmf0Any* any = (SrsAmf0Any*)amf0; @@ -547,6 +600,30 @@ void srs_amf0_free_bytes(char* data) srs_freep(data); } +int srs_amf0_size(srs_amf0_t amf0) +{ + SrsAmf0Any* any = (SrsAmf0Any*)amf0; + return any->total_size(); +} + +int srs_amf0_serialize(srs_amf0_t amf0, char* data, int size) +{ + int ret = ERROR_SUCCESS; + + SrsAmf0Any* any = (SrsAmf0Any*)amf0; + + SrsStream stream; + if ((ret = stream.initialize(data, size)) != ERROR_SUCCESS) { + return ret; + } + + if ((ret = any->write(&stream)) != ERROR_SUCCESS) { + return ret; + } + + return ret; +} + amf0_bool srs_amf0_is_string(srs_amf0_t amf0) { SrsAmf0Any* any = (SrsAmf0Any*)amf0; @@ -625,6 +702,19 @@ srs_amf0_t srs_amf0_object_property_value_at(srs_amf0_t amf0, int index) return (srs_amf0_t)obj->value_at(index); } +srs_amf0_t srs_amf0_object_property(srs_amf0_t amf0, const char* name) +{ + SrsAmf0Object* obj = (SrsAmf0Object*)amf0; + return (srs_amf0_t)obj->get_property(name); +} + +void srs_amf0_object_property_set(srs_amf0_t amf0, const char* name, srs_amf0_t value) +{ + SrsAmf0Object* obj = (SrsAmf0Object*)amf0; + SrsAmf0Any* any = (SrsAmf0Any*)value; + obj->set(name, any); +} + int srs_amf0_ecma_array_property_count(srs_amf0_t amf0) { SrsAmf0EcmaArray * obj = (SrsAmf0EcmaArray*)amf0; @@ -643,16 +733,36 @@ srs_amf0_t srs_amf0_ecma_array_property_value_at(srs_amf0_t amf0, int index) return (srs_amf0_t)obj->value_at(index); } +srs_amf0_t srs_amf0_ecma_array_property(srs_amf0_t amf0, const char* name) +{ + SrsAmf0EcmaArray* obj = (SrsAmf0EcmaArray*)amf0; + return (srs_amf0_t)obj->get_property(name); +} + +void srs_amf0_ecma_array_property_set(srs_amf0_t amf0, const char* name, srs_amf0_t value) +{ + SrsAmf0EcmaArray* obj = (SrsAmf0EcmaArray*)amf0; + SrsAmf0Any* any = (SrsAmf0Any*)value; + obj->set(name, any); +} + int srs_amf0_strict_array_property_count(srs_amf0_t amf0) { - SrsAmf0EcmaArray * obj = (SrsAmf0EcmaArray*)amf0; + SrsAmf0StrictArray * obj = (SrsAmf0StrictArray*)amf0; return obj->count(); } srs_amf0_t srs_amf0_strict_array_property_at(srs_amf0_t amf0, int index) { - SrsAmf0EcmaArray* obj = (SrsAmf0EcmaArray*)amf0; - return (srs_amf0_t)obj->value_at(index); + SrsAmf0StrictArray* obj = (SrsAmf0StrictArray*)amf0; + return (srs_amf0_t)obj->at(index); +} + +void srs_amf0_strict_array_append(srs_amf0_t amf0, srs_amf0_t value) +{ + SrsAmf0StrictArray* obj = (SrsAmf0StrictArray*)amf0; + SrsAmf0Any* any = (SrsAmf0Any*)value; + obj->append(any); } void __srs_fill_level_spaces(stringstream& ss, int level) @@ -735,10 +845,14 @@ char* srs_amf0_human_print(srs_amf0_t amf0, char** pdata, int* psize) memcpy(data, str.data(), str.length()); data[str.length()] = 0; - *pdata = data; - *psize = str.length(); + if (pdata) { + *pdata = data; + } + if (psize) { + *psize = str.length(); + } - return *pdata; + return data; } #ifdef __cplusplus diff --git a/trunk/src/libs/srs_librtmp.hpp b/trunk/src/libs/srs_librtmp.hpp index 59ce79362..d3bd5fde8 100644 --- a/trunk/src/libs/srs_librtmp.hpp +++ b/trunk/src/libs/srs_librtmp.hpp @@ -165,12 +165,23 @@ int srs_flv_read_header(srs_flv_t flv, char header[9]); int srs_flv_read_tag_header(srs_flv_t flv, char* ptype, int32_t* pdata_size, u_int32_t* ptime); /* read the tag data. drop the 4bytes previous tag size */ int srs_flv_read_tag_data(srs_flv_t flv, char* data, int32_t size); +/* write flv header to file, auto write the 4bytes zero previous tag 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); +/* file stream */ /* file stream tellg to get offset */ int64_t srs_flv_tellg(srs_flv_t flv); /* seek file stream, offset is form the start of file */ void srs_flv_lseek(srs_flv_t flv, int64_t offset); +/* error code */ /* whether the error code indicates EOF */ flv_bool srs_flv_is_eof(int error_code); +/* media codec */ +/* whether the video body is sequence header */ +flv_bool srs_flv_is_sequence_header(char* data, int32_t size); +/* whether the video body is keyframe */ +flv_bool srs_flv_is_keyframe(char* data, int32_t size); /** * amf0 codec @@ -180,8 +191,14 @@ typedef void* srs_amf0_t; typedef int amf0_bool; typedef double amf0_number; srs_amf0_t srs_amf0_parse(char* data, int size, int* nparsed); +srs_amf0_t srs_amf0_create_number(amf0_number value); +srs_amf0_t srs_amf0_create_ecma_array(); +srs_amf0_t srs_amf0_create_strict_array(); void srs_amf0_free(srs_amf0_t amf0); void srs_amf0_free_bytes(char* data); +/* size and to bytes */ +int srs_amf0_size(srs_amf0_t amf0); +int srs_amf0_serialize(srs_amf0_t amf0, char* data, int size); /* type detecter */ amf0_bool srs_amf0_is_string(srs_amf0_t amf0); amf0_bool srs_amf0_is_boolean(srs_amf0_t amf0); @@ -198,13 +215,18 @@ amf0_number srs_amf0_to_number(srs_amf0_t amf0); int srs_amf0_object_property_count(srs_amf0_t amf0); const char* srs_amf0_object_property_name_at(srs_amf0_t amf0, int index); srs_amf0_t srs_amf0_object_property_value_at(srs_amf0_t amf0, int index); +srs_amf0_t srs_amf0_object_property(srs_amf0_t amf0, const char* name); +void srs_amf0_object_property_set(srs_amf0_t amf0, const char* name, srs_amf0_t value); /* ecma array value converter */ int srs_amf0_ecma_array_property_count(srs_amf0_t amf0); 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); /* 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); +void srs_amf0_strict_array_append(srs_amf0_t amf0, srs_amf0_t value); /** * human readable print * @param pdata, output the heap data, diff --git a/trunk/src/rtmp/srs_protocol_amf0.cpp b/trunk/src/rtmp/srs_protocol_amf0.cpp index 74d664f1b..716f4ce16 100644 --- a/trunk/src/rtmp/srs_protocol_amf0.cpp +++ b/trunk/src/rtmp/srs_protocol_amf0.cpp @@ -1113,6 +1113,11 @@ SrsAmf0Any* SrsAmf0StrictArray::at(int index) return properties.at(index); } +void SrsAmf0StrictArray::append(SrsAmf0Any* any) +{ + properties.push_back(any); +} + int SrsAmf0Size::utf8(string value) { return 2 + value.length(); diff --git a/trunk/src/rtmp/srs_protocol_amf0.hpp b/trunk/src/rtmp/srs_protocol_amf0.hpp index 0ad88e2cf..df8401958 100644 --- a/trunk/src/rtmp/srs_protocol_amf0.hpp +++ b/trunk/src/rtmp/srs_protocol_amf0.hpp @@ -260,6 +260,7 @@ public: virtual int count(); // @remark: max index is count(). virtual SrsAmf0Any* at(int index); + virtual void append(SrsAmf0Any* any); }; /**