正在显示
10 个修改的文件
包含
309 行增加
和
180 行删除
trunk/research/librtmp/srs_flv_codec.h
已删除
100644 → 0
| 1 | -/* | ||
| 2 | -The MIT License (MIT) | ||
| 3 | - | ||
| 4 | -Copyright (c) 2013-2014 winlin | ||
| 5 | - | ||
| 6 | -Permission is hereby granted, free of charge, to any person obtaining a copy of | ||
| 7 | -this software and associated documentation files (the "Software"), to deal in | ||
| 8 | -the Software without restriction, including without limitation the rights to | ||
| 9 | -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of | ||
| 10 | -the Software, and to permit persons to whom the Software is furnished to do so, | ||
| 11 | -subject to the following conditions: | ||
| 12 | - | ||
| 13 | -The above copyright notice and this permission notice shall be included in all | ||
| 14 | -copies or substantial portions of the Software. | ||
| 15 | - | ||
| 16 | -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS | ||
| 18 | -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | ||
| 19 | -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | ||
| 20 | -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
| 21 | -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 22 | -*/ | ||
| 23 | - | ||
| 24 | -#ifndef SRS_RESEARH_FLV_CODEC_HPP | ||
| 25 | -#define SRS_RESEARH_FLV_CODEC_HPP | ||
| 26 | - | ||
| 27 | -/* | ||
| 28 | -#include "srs_flv_codec.h" | ||
| 29 | -*/ | ||
| 30 | - | ||
| 31 | -#include <unistd.h> | ||
| 32 | -#include <fcntl.h> | ||
| 33 | -#include <sys/stat.h> | ||
| 34 | -#include <sys/types.h> | ||
| 35 | - | ||
| 36 | -#define ERROR_FLV_CODEC_EOF 100 | ||
| 37 | - | ||
| 38 | -int open_flv_file(char* in_flv_file) | ||
| 39 | -{ | ||
| 40 | - return open(in_flv_file, O_RDONLY); | ||
| 41 | -} | ||
| 42 | - | ||
| 43 | -void close_flv_file(int fd) | ||
| 44 | -{ | ||
| 45 | - if (fd > 0) { | ||
| 46 | - close(fd); | ||
| 47 | - } | ||
| 48 | -} | ||
| 49 | - | ||
| 50 | -int flv_open_ic(int flv_fd) | ||
| 51 | -{ | ||
| 52 | - int ret = 0; | ||
| 53 | - | ||
| 54 | - char h[13]; // 9+4 | ||
| 55 | - | ||
| 56 | - if (read(flv_fd, h, sizeof(h)) != sizeof(h)) { | ||
| 57 | - ret = -1; | ||
| 58 | - trace("read flv header failed. ret=%d", ret); | ||
| 59 | - return ret; | ||
| 60 | - } | ||
| 61 | - | ||
| 62 | - if (h[0] != 'F' || h[1] != 'L' || h[2] != 'V') { | ||
| 63 | - ret = -1; | ||
| 64 | - trace("input is not a flv file. ret=%d", ret); | ||
| 65 | - return ret; | ||
| 66 | - } | ||
| 67 | - | ||
| 68 | - return ret; | ||
| 69 | -} | ||
| 70 | - | ||
| 71 | -int flv_read_packet(int flv_fd, int* type, u_int32_t* timestamp, char** data, int* size) | ||
| 72 | -{ | ||
| 73 | - int ret = 0; | ||
| 74 | - | ||
| 75 | - char th[11]; // tag header | ||
| 76 | - char ts[4]; // tag size | ||
| 77 | - | ||
| 78 | - int32_t data_size = 0; | ||
| 79 | - u_int32_t time = 0; | ||
| 80 | - | ||
| 81 | - char* pp; | ||
| 82 | - | ||
| 83 | - // read tag header | ||
| 84 | - if ((ret = read(flv_fd, th, sizeof(th))) != sizeof(th)) { | ||
| 85 | - if (ret == 0) { | ||
| 86 | - return ERROR_FLV_CODEC_EOF; | ||
| 87 | - } | ||
| 88 | - ret = -1; | ||
| 89 | - trace("read flv tag header failed. ret=%d", ret); | ||
| 90 | - return ret; | ||
| 91 | - } | ||
| 92 | - | ||
| 93 | - // Reserved UB [2] | ||
| 94 | - // Filter UB [1] | ||
| 95 | - // TagType UB [5] | ||
| 96 | - *type = (int)(th[0] & 0x1F); | ||
| 97 | - | ||
| 98 | - // DataSize UI24 | ||
| 99 | - pp = (char*)&data_size; | ||
| 100 | - pp[2] = th[1]; | ||
| 101 | - pp[1] = th[2]; | ||
| 102 | - pp[0] = th[3]; | ||
| 103 | - | ||
| 104 | - // Timestamp UI24 | ||
| 105 | - pp = (char*)&time; | ||
| 106 | - pp[2] = th[4]; | ||
| 107 | - pp[1] = th[5]; | ||
| 108 | - pp[0] = th[6]; | ||
| 109 | - | ||
| 110 | - // TimestampExtended UI8 | ||
| 111 | - pp[3] = th[7]; | ||
| 112 | - | ||
| 113 | - *timestamp = time; | ||
| 114 | - | ||
| 115 | - // check data size. | ||
| 116 | - if (data_size <= 0) { | ||
| 117 | - ret = -1; | ||
| 118 | - trace("invalid data size. size=%d, ret=%d", data_size, ret); | ||
| 119 | - return ret; | ||
| 120 | - } | ||
| 121 | - | ||
| 122 | - // read tag data. | ||
| 123 | - *size = data_size; | ||
| 124 | - *data = (char*)malloc(data_size); | ||
| 125 | - if ((ret = read(flv_fd, *data, data_size)) != data_size) { | ||
| 126 | - if (ret == 0) { | ||
| 127 | - return ERROR_FLV_CODEC_EOF; | ||
| 128 | - } | ||
| 129 | - ret = -1; | ||
| 130 | - trace("read flv tag data failed. size=%d, ret=%d", data_size, ret); | ||
| 131 | - return ret; | ||
| 132 | - } | ||
| 133 | - | ||
| 134 | - // ignore 4bytes tag size. | ||
| 135 | - if ((ret = read(flv_fd, ts, sizeof(ts))) != sizeof(ts)) { | ||
| 136 | - if (ret == 0) { | ||
| 137 | - return ERROR_FLV_CODEC_EOF; | ||
| 138 | - } | ||
| 139 | - ret = -1; | ||
| 140 | - trace("read flv tag size failed. ret=%d", ret); | ||
| 141 | - return ret; | ||
| 142 | - } | ||
| 143 | - | ||
| 144 | - return 0; | ||
| 145 | -} | ||
| 146 | - | ||
| 147 | -#endif |
| @@ -34,7 +34,8 @@ gcc srs_flv_injecter.c ../../objs/lib/srs_librtmp.a -g -O0 -lstdc++ -o srs_flv_i | @@ -34,7 +34,8 @@ gcc srs_flv_injecter.c ../../objs/lib/srs_librtmp.a -g -O0 -lstdc++ -o srs_flv_i | ||
| 34 | 34 | ||
| 35 | #include "../../objs/include/srs_librtmp.h" | 35 | #include "../../objs/include/srs_librtmp.h" |
| 36 | #include "srs_research_public.h" | 36 | #include "srs_research_public.h" |
| 37 | -#include "srs_flv_codec.h" | 37 | + |
| 38 | +#define ERROR_INJECTED 10000 | ||
| 38 | 39 | ||
| 39 | int process(const char* in_flv_file, const char* out_flv_file, srs_flv_t* pic, srs_flv_t* poc); | 40 | int process(const char* in_flv_file, const char* out_flv_file, srs_flv_t* pic, srs_flv_t* poc); |
| 40 | int inject_flv(srs_flv_t ic, srs_flv_t oc); | 41 | int inject_flv(srs_flv_t ic, srs_flv_t oc); |
| @@ -87,7 +88,12 @@ int main(int argc, char** argv) | @@ -87,7 +88,12 @@ int main(int argc, char** argv) | ||
| 87 | 88 | ||
| 88 | if (ret != 0) { | 89 | if (ret != 0) { |
| 89 | unlink(tmp_file); | 90 | unlink(tmp_file); |
| 90 | - trace("error, remove tmp file."); | 91 | + if (ret == ERROR_INJECTED) { |
| 92 | + ret = 0; | ||
| 93 | + trace("file already injected."); | ||
| 94 | + } else { | ||
| 95 | + trace("error, remove tmp file."); | ||
| 96 | + } | ||
| 91 | } else { | 97 | } else { |
| 92 | rename(tmp_file, out_flv_file); | 98 | rename(tmp_file, out_flv_file); |
| 93 | trace("completed, rename to %s", out_flv_file); | 99 | trace("completed, rename to %s", out_flv_file); |
| @@ -153,25 +159,32 @@ int inject_flv(srs_flv_t ic, srs_flv_t oc) | @@ -153,25 +159,32 @@ int inject_flv(srs_flv_t ic, srs_flv_t oc) | ||
| 153 | u_int32_t timestamp = 0; | 159 | u_int32_t timestamp = 0; |
| 154 | char* data = NULL; | 160 | char* data = NULL; |
| 155 | int32_t size; | 161 | int32_t size; |
| 162 | + int64_t offset = 0; | ||
| 156 | 163 | ||
| 157 | // metadata | 164 | // metadata |
| 158 | srs_amf0_t amf0_name = NULL; | 165 | srs_amf0_t amf0_name = NULL; |
| 166 | + int amf0_name_size = 0; | ||
| 159 | srs_amf0_t amf0_data = NULL; | 167 | srs_amf0_t amf0_data = NULL; |
| 168 | + srs_amf0_t keyframes = NULL; | ||
| 169 | + srs_amf0_t filepositions = NULL; | ||
| 170 | + srs_amf0_t times = NULL; | ||
| 160 | 171 | ||
| 161 | // reset to generate metadata | 172 | // reset to generate metadata |
| 162 | srs_flv_lseek(ic, 0); | 173 | srs_flv_lseek(ic, 0); |
| 163 | 174 | ||
| 164 | - if ((ret = srs_flv_read_header(oc, header)) != 0) { | 175 | + if ((ret = srs_flv_read_header(ic, header)) != 0) { |
| 165 | return ret; | 176 | return ret; |
| 166 | } | 177 | } |
| 167 | 178 | ||
| 168 | - trace("start inject flv"); | 179 | + trace("build keyframe infos from flv"); |
| 169 | for (;;) { | 180 | for (;;) { |
| 181 | + offset = srs_flv_tellg(ic); | ||
| 182 | + | ||
| 170 | // tag header | 183 | // tag header |
| 171 | - if ((ret = srs_flv_read_tag_header(oc, &type, &size, ×tamp)) != 0) { | 184 | + if ((ret = srs_flv_read_tag_header(ic, &type, &size, ×tamp)) != 0) { |
| 172 | if (srs_flv_is_eof(ret)) { | 185 | if (srs_flv_is_eof(ret)) { |
| 173 | trace("parse completed."); | 186 | trace("parse completed."); |
| 174 | - return 0; | 187 | + break; |
| 175 | } | 188 | } |
| 176 | trace("flv get packet failed. ret=%d", ret); | 189 | trace("flv get packet failed. ret=%d", ret); |
| 177 | return ret; | 190 | return ret; |
| @@ -184,16 +197,107 @@ int inject_flv(srs_flv_t ic, srs_flv_t oc) | @@ -184,16 +197,107 @@ int inject_flv(srs_flv_t ic, srs_flv_t oc) | ||
| 184 | 197 | ||
| 185 | // TODO: FIXME: mem leak when error. | 198 | // TODO: FIXME: mem leak when error. |
| 186 | data = (char*)malloc(size); | 199 | data = (char*)malloc(size); |
| 187 | - if ((ret = srs_flv_read_tag_data(oc, data, size)) != 0) { | 200 | + if ((ret = srs_flv_read_tag_data(ic, data, size)) != 0) { |
| 188 | return ret; | 201 | return ret; |
| 189 | } | 202 | } |
| 190 | 203 | ||
| 191 | // data tag | 204 | // data tag |
| 192 | if (type == SRS_RTMP_TYPE_VIDEO) { | 205 | if (type == SRS_RTMP_TYPE_VIDEO) { |
| 206 | + if (!srs_flv_is_sequence_header(data, size) && srs_flv_is_keyframe(data, size)) { | ||
| 207 | + srs_amf0_strict_array_append(filepositions, srs_amf0_create_number(offset)); | ||
| 208 | + srs_amf0_strict_array_append(times, srs_amf0_create_number(((double)timestamp)/ 1000)); | ||
| 209 | + } | ||
| 193 | } else if (type == SRS_RTMP_TYPE_SCRIPT) { | 210 | } else if (type == SRS_RTMP_TYPE_SCRIPT) { |
| 194 | if ((ret = parse_metadata(data, size, &amf0_name, &amf0_data)) != 0) { | 211 | if ((ret = parse_metadata(data, size, &amf0_name, &amf0_data)) != 0) { |
| 195 | return ret; | 212 | return ret; |
| 196 | } | 213 | } |
| 214 | + | ||
| 215 | + if (srs_amf0_is_object(amf0_data)) { | ||
| 216 | + keyframes = srs_amf0_object_property(amf0_data, "keyframes"); | ||
| 217 | + if (keyframes != NULL) { | ||
| 218 | + return 0; | ||
| 219 | + } | ||
| 220 | + keyframes = srs_amf0_create_ecma_array(); | ||
| 221 | + srs_amf0_object_property_set(amf0_data, "keyframes", keyframes); | ||
| 222 | + filepositions = srs_amf0_create_strict_array(); | ||
| 223 | + srs_amf0_object_property_set(keyframes, "filepositions", filepositions); | ||
| 224 | + times = srs_amf0_create_strict_array(); | ||
| 225 | + srs_amf0_object_property_set(keyframes, "times", times); | ||
| 226 | + } else if (srs_amf0_is_ecma_array(amf0_data)) { | ||
| 227 | + keyframes = srs_amf0_ecma_array_property(amf0_data, "keyframes"); | ||
| 228 | + if (keyframes != NULL) { | ||
| 229 | + return 0; | ||
| 230 | + } | ||
| 231 | + keyframes = srs_amf0_create_ecma_array(); | ||
| 232 | + srs_amf0_ecma_array_property_set(amf0_data, "keyframes", keyframes); | ||
| 233 | + filepositions = srs_amf0_create_strict_array(); | ||
| 234 | + srs_amf0_ecma_array_property_set(keyframes, "filepositions", filepositions); | ||
| 235 | + times = srs_amf0_create_strict_array(); | ||
| 236 | + srs_amf0_ecma_array_property_set(keyframes, "times", times); | ||
| 237 | + } | ||
| 238 | + } | ||
| 239 | + | ||
| 240 | + free(data); | ||
| 241 | + } | ||
| 242 | + | ||
| 243 | + // reset to write injected file | ||
| 244 | + srs_flv_lseek(ic, 0); | ||
| 245 | + | ||
| 246 | + if ((ret = srs_flv_read_header(ic, header)) != 0) { | ||
| 247 | + return ret; | ||
| 248 | + } | ||
| 249 | + | ||
| 250 | + if ((ret = srs_flv_write_header(oc, header)) != 0) { | ||
| 251 | + return ret; | ||
| 252 | + } | ||
| 253 | + | ||
| 254 | + // write metadata | ||
| 255 | + if (amf0_name != NULL && amf0_data != NULL) { | ||
| 256 | + amf0_name_size = srs_amf0_size(amf0_name); | ||
| 257 | + size = amf0_name_size + srs_amf0_size(amf0_data); | ||
| 258 | + data = (char*)malloc(size); | ||
| 259 | + if ((ret = srs_amf0_serialize(amf0_name, data, amf0_name_size)) != 0) { | ||
| 260 | + return ret; | ||
| 261 | + } | ||
| 262 | + if ((ret = srs_amf0_serialize(amf0_data, data + amf0_name_size, size - amf0_name_size)) != 0) { | ||
| 263 | + return ret; | ||
| 264 | + } | ||
| 265 | + if ((ret = srs_flv_write_tag(oc, SRS_RTMP_TYPE_SCRIPT, 0, data, size)) != 0) { | ||
| 266 | + return ret; | ||
| 267 | + } | ||
| 268 | + free(data); | ||
| 269 | + } | ||
| 270 | + trace("build keyframe infos from flv"); | ||
| 271 | + for (;;) { | ||
| 272 | + // tag header | ||
| 273 | + if ((ret = srs_flv_read_tag_header(ic, &type, &size, ×tamp)) != 0) { | ||
| 274 | + if (srs_flv_is_eof(ret)) { | ||
| 275 | + trace("parse completed."); | ||
| 276 | + return 0; | ||
| 277 | + } | ||
| 278 | + trace("flv get packet failed. ret=%d", ret); | ||
| 279 | + return ret; | ||
| 280 | + } | ||
| 281 | + | ||
| 282 | + if (size <= 0) { | ||
| 283 | + trace("invalid size=%d", size); | ||
| 284 | + break; | ||
| 285 | + } | ||
| 286 | + | ||
| 287 | + // TODO: FIXME: mem leak when error. | ||
| 288 | + data = (char*)malloc(size); | ||
| 289 | + if ((ret = srs_flv_read_tag_data(ic, data, size)) != 0) { | ||
| 290 | + return ret; | ||
| 291 | + } | ||
| 292 | + | ||
| 293 | + // data tag | ||
| 294 | + if (type == SRS_RTMP_TYPE_SCRIPT) { | ||
| 295 | + continue; | ||
| 296 | + } | ||
| 297 | + | ||
| 298 | + // copy | ||
| 299 | + if ((ret = srs_flv_write_tag(oc, type, timestamp, data, size)) != 0) { | ||
| 300 | + return ret; | ||
| 197 | } | 301 | } |
| 198 | 302 | ||
| 199 | free(data); | 303 | free(data); |
| @@ -34,7 +34,6 @@ gcc srs_ingest_flv.c ../../objs/lib/srs_librtmp.a -g -O0 -lstdc++ -o srs_ingest_ | @@ -34,7 +34,6 @@ gcc srs_ingest_flv.c ../../objs/lib/srs_librtmp.a -g -O0 -lstdc++ -o srs_ingest_ | ||
| 34 | 34 | ||
| 35 | #include "../../objs/include/srs_librtmp.h" | 35 | #include "../../objs/include/srs_librtmp.h" |
| 36 | #include "srs_research_public.h" | 36 | #include "srs_research_public.h" |
| 37 | -#include "srs_flv_codec.h" | ||
| 38 | 37 | ||
| 39 | int parse_flv(srs_flv_t flv); | 38 | int parse_flv(srs_flv_t flv); |
| 40 | int main(int argc, char** argv) | 39 | int main(int argc, char** argv) |
| @@ -34,9 +34,8 @@ gcc srs_ingest_flv.c ../../objs/lib/srs_librtmp.a -g -O0 -lstdc++ -o srs_ingest_ | @@ -34,9 +34,8 @@ gcc srs_ingest_flv.c ../../objs/lib/srs_librtmp.a -g -O0 -lstdc++ -o srs_ingest_ | ||
| 34 | 34 | ||
| 35 | #include "../../objs/include/srs_librtmp.h" | 35 | #include "../../objs/include/srs_librtmp.h" |
| 36 | #include "srs_research_public.h" | 36 | #include "srs_research_public.h" |
| 37 | -#include "srs_flv_codec.h" | ||
| 38 | 37 | ||
| 39 | -int proxy(int flv_fd, srs_rtmp_t ortmp); | 38 | +int proxy(srs_flv_t flv, srs_rtmp_t ortmp); |
| 40 | int connect_oc(srs_rtmp_t ortmp); | 39 | int connect_oc(srs_rtmp_t ortmp); |
| 41 | 40 | ||
| 42 | #define RE_PULSE_MS 300 | 41 | #define RE_PULSE_MS 300 |
| @@ -59,7 +58,7 @@ int main(int argc, char** argv) | @@ -59,7 +58,7 @@ int main(int argc, char** argv) | ||
| 59 | // rtmp handler | 58 | // rtmp handler |
| 60 | srs_rtmp_t ortmp; | 59 | srs_rtmp_t ortmp; |
| 61 | // flv handler | 60 | // flv handler |
| 62 | - int flv_fd; | 61 | + srs_flv_t flv; |
| 63 | 62 | ||
| 64 | if (argc <= 2) { | 63 | if (argc <= 2) { |
| 65 | printf("ingest flv file and publish to RTMP server\n" | 64 | printf("ingest flv file and publish to RTMP server\n" |
| @@ -94,8 +93,7 @@ int main(int argc, char** argv) | @@ -94,8 +93,7 @@ int main(int argc, char** argv) | ||
| 94 | trace("input: %s", in_flv_file); | 93 | trace("input: %s", in_flv_file); |
| 95 | trace("output: %s", out_rtmp_url); | 94 | trace("output: %s", out_rtmp_url); |
| 96 | 95 | ||
| 97 | - flv_fd = open_flv_file(in_flv_file); | ||
| 98 | - if (flv_fd <= 0) { | 96 | + if ((flv = srs_flv_open_read(in_flv_file)) == NULL) { |
| 99 | ret = 2; | 97 | ret = 2; |
| 100 | trace("open flv file failed. ret=%d", ret); | 98 | trace("open flv file failed. ret=%d", ret); |
| 101 | return ret; | 99 | return ret; |
| @@ -103,31 +101,46 @@ int main(int argc, char** argv) | @@ -103,31 +101,46 @@ int main(int argc, char** argv) | ||
| 103 | 101 | ||
| 104 | ortmp = srs_rtmp_create(out_rtmp_url); | 102 | ortmp = srs_rtmp_create(out_rtmp_url); |
| 105 | 103 | ||
| 106 | - ret = proxy(flv_fd, ortmp); | 104 | + ret = proxy(flv, ortmp); |
| 107 | trace("ingest flv to RTMP completed"); | 105 | trace("ingest flv to RTMP completed"); |
| 108 | 106 | ||
| 109 | srs_rtmp_destroy(ortmp); | 107 | srs_rtmp_destroy(ortmp); |
| 110 | - close_flv_file(flv_fd); | 108 | + srs_flv_close(flv); |
| 111 | 109 | ||
| 112 | return ret; | 110 | return ret; |
| 113 | } | 111 | } |
| 114 | 112 | ||
| 115 | -int do_proxy(int flv_fd, srs_rtmp_t ortmp, int64_t re, u_int32_t* ptimestamp) | 113 | +int do_proxy(srs_flv_t flv, srs_rtmp_t ortmp, int64_t re, u_int32_t* ptimestamp) |
| 116 | { | 114 | { |
| 117 | int ret = 0; | 115 | int ret = 0; |
| 118 | 116 | ||
| 119 | // packet data | 117 | // packet data |
| 120 | - int type, size; | 118 | + char type; |
| 119 | + int size; | ||
| 121 | char* data = NULL; | 120 | char* data = NULL; |
| 122 | 121 | ||
| 123 | trace("start ingest flv to RTMP stream"); | 122 | trace("start ingest flv to RTMP stream"); |
| 124 | for (;;) { | 123 | for (;;) { |
| 125 | - if ((ret = flv_read_packet(flv_fd, &type, ptimestamp, &data, &size)) != 0) { | ||
| 126 | - trace("irtmp get packet failed. ret=%d", ret); | 124 | + // tag header |
| 125 | + if ((ret = srs_flv_read_tag_header(flv, &type, &size, ptimestamp)) != 0) { | ||
| 126 | + if (srs_flv_is_eof(ret)) { | ||
| 127 | + trace("parse completed."); | ||
| 128 | + return 0; | ||
| 129 | + } | ||
| 130 | + trace("flv get packet failed. ret=%d", ret); | ||
| 131 | + return ret; | ||
| 132 | + } | ||
| 133 | + | ||
| 134 | + if (size <= 0) { | ||
| 135 | + trace("invalid size=%d", size); | ||
| 136 | + break; | ||
| 137 | + } | ||
| 138 | + | ||
| 139 | + // TODO: FIXME: mem leak when error. | ||
| 140 | + data = (char*)malloc(size); | ||
| 141 | + if ((ret = srs_flv_read_tag_data(flv, data, size)) != 0) { | ||
| 127 | return ret; | 142 | return ret; |
| 128 | } | 143 | } |
| 129 | - verbose("irtmp got packet: type=%s, time=%d, size=%d", | ||
| 130 | - srs_type2string(type), timestamp, size); | ||
| 131 | 144 | ||
| 132 | if ((ret = srs_write_packet(ortmp, type, *ptimestamp, data, size)) != 0) { | 145 | if ((ret = srs_write_packet(ortmp, type, *ptimestamp, data, size)) != 0) { |
| 133 | trace("irtmp get packet failed. ret=%d", ret); | 146 | 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) | @@ -142,12 +155,13 @@ int do_proxy(int flv_fd, srs_rtmp_t ortmp, int64_t re, u_int32_t* ptimestamp) | ||
| 142 | return ret; | 155 | return ret; |
| 143 | } | 156 | } |
| 144 | 157 | ||
| 145 | -int proxy(int flv_fd, srs_rtmp_t ortmp) | 158 | +int proxy(srs_flv_t flv, srs_rtmp_t ortmp) |
| 146 | { | 159 | { |
| 147 | int ret = 0; | 160 | int ret = 0; |
| 148 | u_int32_t timestamp = 0; | 161 | u_int32_t timestamp = 0; |
| 149 | 162 | ||
| 150 | - if ((ret = flv_open_ic(flv_fd)) != 0) { | 163 | + char header[13]; |
| 164 | + if ((ret = srs_flv_read_header(flv, header)) != 0) { | ||
| 151 | return ret; | 165 | return ret; |
| 152 | } | 166 | } |
| 153 | if ((ret = connect_oc(ortmp)) != 0) { | 167 | if ((ret = connect_oc(ortmp)) != 0) { |
| @@ -156,7 +170,7 @@ int proxy(int flv_fd, srs_rtmp_t ortmp) | @@ -156,7 +170,7 @@ int proxy(int flv_fd, srs_rtmp_t ortmp) | ||
| 156 | 170 | ||
| 157 | int64_t re = re_create(); | 171 | int64_t re = re_create(); |
| 158 | 172 | ||
| 159 | - ret = do_proxy(flv_fd, ortmp, re, ×tamp); | 173 | + ret = do_proxy(flv, ortmp, re, ×tamp); |
| 160 | 174 | ||
| 161 | // for the last pulse, always sleep. | 175 | // for the last pulse, always sleep. |
| 162 | re_cleanup(re, timestamp); | 176 | re_cleanup(re, timestamp); |
| @@ -207,20 +207,36 @@ int SrsFlvEncoder::write_header() | @@ -207,20 +207,36 @@ int SrsFlvEncoder::write_header() | ||
| 207 | 'F', 'L', 'V', // Signatures "FLV" | 207 | 'F', 'L', 'V', // Signatures "FLV" |
| 208 | (char)0x01, // File version (for example, 0x01 for FLV version 1) | 208 | (char)0x01, // File version (for example, 0x01 for FLV version 1) |
| 209 | (char)0x00, // 4, audio; 1, video; 5 audio+video. | 209 | (char)0x00, // 4, audio; 1, video; 5 audio+video. |
| 210 | - (char)0x00, (char)0x00, (char)0x00, (char)0x09, // DataOffset UI32 The length of this header in bytes | ||
| 211 | - (char)0x00, (char)0x00, (char)0x00, (char)0x00// PreviousTagSize0 UI32 Always 0 | 210 | + (char)0x00, (char)0x00, (char)0x00, (char)0x09 // DataOffset UI32 The length of this header in bytes |
| 212 | }; | 211 | }; |
| 213 | 212 | ||
| 214 | // flv specification should set the audio and video flag, | 213 | // flv specification should set the audio and video flag, |
| 215 | // actually in practise, application generally ignore this flag, | 214 | // actually in practise, application generally ignore this flag, |
| 216 | // so we generally set the audio/video to 0. | 215 | // so we generally set the audio/video to 0. |
| 217 | 216 | ||
| 217 | + // write 9bytes header. | ||
| 218 | + if ((ret = write_header(flv_header)) != ERROR_SUCCESS) { | ||
| 219 | + return ret; | ||
| 220 | + } | ||
| 221 | + | ||
| 222 | + return ret; | ||
| 223 | +} | ||
| 224 | + | ||
| 225 | +int SrsFlvEncoder::write_header(char flv_header[9]) | ||
| 226 | +{ | ||
| 227 | + int ret = ERROR_SUCCESS; | ||
| 228 | + | ||
| 218 | // write data. | 229 | // write data. |
| 219 | - if ((ret = _fs->write(flv_header, sizeof(flv_header), NULL)) != ERROR_SUCCESS) { | 230 | + if ((ret = _fs->write(flv_header, 9, NULL)) != ERROR_SUCCESS) { |
| 220 | srs_error("write flv header failed. ret=%d", ret); | 231 | srs_error("write flv header failed. ret=%d", ret); |
| 221 | return ret; | 232 | return ret; |
| 222 | } | 233 | } |
| 223 | 234 | ||
| 235 | + char pts[] = { 0x00, 0x00, 0x00, 0x00 }; | ||
| 236 | + if ((ret = _fs->write(pts, 4, NULL)) != ERROR_SUCCESS) { | ||
| 237 | + return ret; | ||
| 238 | + } | ||
| 239 | + | ||
| 224 | return ret; | 240 | return ret; |
| 225 | } | 241 | } |
| 226 | 242 |
| @@ -92,6 +92,7 @@ public: | @@ -92,6 +92,7 @@ public: | ||
| 92 | * that is, 9+4=13bytes. | 92 | * that is, 9+4=13bytes. |
| 93 | */ | 93 | */ |
| 94 | virtual int write_header(); | 94 | virtual int write_header(); |
| 95 | + virtual int write_header(char flv_header[9]); | ||
| 95 | /** | 96 | /** |
| 96 | * write flv metadata. | 97 | * write flv metadata. |
| 97 | * serialize from: | 98 | * serialize from: |
| @@ -491,6 +491,34 @@ int srs_flv_read_tag_data(srs_flv_t flv, char* data, int32_t size) | @@ -491,6 +491,34 @@ int srs_flv_read_tag_data(srs_flv_t flv, char* data, int32_t size) | ||
| 491 | return ret; | 491 | return ret; |
| 492 | } | 492 | } |
| 493 | 493 | ||
| 494 | +int srs_flv_write_header(srs_flv_t flv, char header[9]) | ||
| 495 | +{ | ||
| 496 | + int ret = ERROR_SUCCESS; | ||
| 497 | + | ||
| 498 | + FlvContext* context = (FlvContext*)flv; | ||
| 499 | + if ((ret = context->enc.write_header(header)) != ERROR_SUCCESS) { | ||
| 500 | + return ret; | ||
| 501 | + } | ||
| 502 | + | ||
| 503 | + return ret; | ||
| 504 | +} | ||
| 505 | + | ||
| 506 | +int srs_flv_write_tag(srs_flv_t flv, char type, int32_t time, char* data, int size) | ||
| 507 | +{ | ||
| 508 | + int ret = ERROR_SUCCESS; | ||
| 509 | + | ||
| 510 | + FlvContext* context = (FlvContext*)flv; | ||
| 511 | + if (type == SRS_RTMP_TYPE_AUDIO) { | ||
| 512 | + return context->enc.write_audio(time, data, size); | ||
| 513 | + } else if (type == SRS_RTMP_TYPE_VIDEO) { | ||
| 514 | + return context->enc.write_video(time, data, size); | ||
| 515 | + } else { | ||
| 516 | + return context->enc.write_metadata(data, size); | ||
| 517 | + } | ||
| 518 | + | ||
| 519 | + return ret; | ||
| 520 | +} | ||
| 521 | + | ||
| 494 | int64_t srs_flv_tellg(srs_flv_t flv) | 522 | int64_t srs_flv_tellg(srs_flv_t flv) |
| 495 | { | 523 | { |
| 496 | FlvContext* context = (FlvContext*)flv; | 524 | FlvContext* context = (FlvContext*)flv; |
| @@ -508,6 +536,16 @@ flv_bool srs_flv_is_eof(int error_code) | @@ -508,6 +536,16 @@ flv_bool srs_flv_is_eof(int error_code) | ||
| 508 | return error_code == ERROR_SYSTEM_FILE_EOF; | 536 | return error_code == ERROR_SYSTEM_FILE_EOF; |
| 509 | } | 537 | } |
| 510 | 538 | ||
| 539 | +flv_bool srs_flv_is_sequence_header(char* data, int32_t size) | ||
| 540 | +{ | ||
| 541 | + return SrsCodec::video_is_sequence_header((int8_t*)data, (int)size); | ||
| 542 | +} | ||
| 543 | + | ||
| 544 | +flv_bool srs_flv_is_keyframe(char* data, int32_t size) | ||
| 545 | +{ | ||
| 546 | + return SrsCodec::video_is_keyframe((int8_t*)data, (int)size); | ||
| 547 | +} | ||
| 548 | + | ||
| 511 | srs_amf0_t srs_amf0_parse(char* data, int size, int* nparsed) | 549 | srs_amf0_t srs_amf0_parse(char* data, int size, int* nparsed) |
| 512 | { | 550 | { |
| 513 | int ret = ERROR_SUCCESS; | 551 | int ret = ERROR_SUCCESS; |
| @@ -536,6 +574,21 @@ srs_amf0_t srs_amf0_parse(char* data, int size, int* nparsed) | @@ -536,6 +574,21 @@ srs_amf0_t srs_amf0_parse(char* data, int size, int* nparsed) | ||
| 536 | return amf0; | 574 | return amf0; |
| 537 | } | 575 | } |
| 538 | 576 | ||
| 577 | +srs_amf0_t srs_amf0_create_number(amf0_number value) | ||
| 578 | +{ | ||
| 579 | + return SrsAmf0Any::number(value); | ||
| 580 | +} | ||
| 581 | + | ||
| 582 | +srs_amf0_t srs_amf0_create_ecma_array() | ||
| 583 | +{ | ||
| 584 | + return SrsAmf0Any::ecma_array(); | ||
| 585 | +} | ||
| 586 | + | ||
| 587 | +srs_amf0_t srs_amf0_create_strict_array() | ||
| 588 | +{ | ||
| 589 | + return SrsAmf0Any::strict_array(); | ||
| 590 | +} | ||
| 591 | + | ||
| 539 | void srs_amf0_free(srs_amf0_t amf0) | 592 | void srs_amf0_free(srs_amf0_t amf0) |
| 540 | { | 593 | { |
| 541 | SrsAmf0Any* any = (SrsAmf0Any*)amf0; | 594 | SrsAmf0Any* any = (SrsAmf0Any*)amf0; |
| @@ -547,6 +600,30 @@ void srs_amf0_free_bytes(char* data) | @@ -547,6 +600,30 @@ void srs_amf0_free_bytes(char* data) | ||
| 547 | srs_freep(data); | 600 | srs_freep(data); |
| 548 | } | 601 | } |
| 549 | 602 | ||
| 603 | +int srs_amf0_size(srs_amf0_t amf0) | ||
| 604 | +{ | ||
| 605 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 606 | + return any->total_size(); | ||
| 607 | +} | ||
| 608 | + | ||
| 609 | +int srs_amf0_serialize(srs_amf0_t amf0, char* data, int size) | ||
| 610 | +{ | ||
| 611 | + int ret = ERROR_SUCCESS; | ||
| 612 | + | ||
| 613 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 614 | + | ||
| 615 | + SrsStream stream; | ||
| 616 | + if ((ret = stream.initialize(data, size)) != ERROR_SUCCESS) { | ||
| 617 | + return ret; | ||
| 618 | + } | ||
| 619 | + | ||
| 620 | + if ((ret = any->write(&stream)) != ERROR_SUCCESS) { | ||
| 621 | + return ret; | ||
| 622 | + } | ||
| 623 | + | ||
| 624 | + return ret; | ||
| 625 | +} | ||
| 626 | + | ||
| 550 | amf0_bool srs_amf0_is_string(srs_amf0_t amf0) | 627 | amf0_bool srs_amf0_is_string(srs_amf0_t amf0) |
| 551 | { | 628 | { |
| 552 | SrsAmf0Any* any = (SrsAmf0Any*)amf0; | 629 | SrsAmf0Any* any = (SrsAmf0Any*)amf0; |
| @@ -625,6 +702,19 @@ srs_amf0_t srs_amf0_object_property_value_at(srs_amf0_t amf0, int index) | @@ -625,6 +702,19 @@ srs_amf0_t srs_amf0_object_property_value_at(srs_amf0_t amf0, int index) | ||
| 625 | return (srs_amf0_t)obj->value_at(index); | 702 | return (srs_amf0_t)obj->value_at(index); |
| 626 | } | 703 | } |
| 627 | 704 | ||
| 705 | +srs_amf0_t srs_amf0_object_property(srs_amf0_t amf0, const char* name) | ||
| 706 | +{ | ||
| 707 | + SrsAmf0Object* obj = (SrsAmf0Object*)amf0; | ||
| 708 | + return (srs_amf0_t)obj->get_property(name); | ||
| 709 | +} | ||
| 710 | + | ||
| 711 | +void srs_amf0_object_property_set(srs_amf0_t amf0, const char* name, srs_amf0_t value) | ||
| 712 | +{ | ||
| 713 | + SrsAmf0Object* obj = (SrsAmf0Object*)amf0; | ||
| 714 | + SrsAmf0Any* any = (SrsAmf0Any*)value; | ||
| 715 | + obj->set(name, any); | ||
| 716 | +} | ||
| 717 | + | ||
| 628 | int srs_amf0_ecma_array_property_count(srs_amf0_t amf0) | 718 | int srs_amf0_ecma_array_property_count(srs_amf0_t amf0) |
| 629 | { | 719 | { |
| 630 | SrsAmf0EcmaArray * obj = (SrsAmf0EcmaArray*)amf0; | 720 | SrsAmf0EcmaArray * obj = (SrsAmf0EcmaArray*)amf0; |
| @@ -643,16 +733,36 @@ srs_amf0_t srs_amf0_ecma_array_property_value_at(srs_amf0_t amf0, int index) | @@ -643,16 +733,36 @@ srs_amf0_t srs_amf0_ecma_array_property_value_at(srs_amf0_t amf0, int index) | ||
| 643 | return (srs_amf0_t)obj->value_at(index); | 733 | return (srs_amf0_t)obj->value_at(index); |
| 644 | } | 734 | } |
| 645 | 735 | ||
| 736 | +srs_amf0_t srs_amf0_ecma_array_property(srs_amf0_t amf0, const char* name) | ||
| 737 | +{ | ||
| 738 | + SrsAmf0EcmaArray* obj = (SrsAmf0EcmaArray*)amf0; | ||
| 739 | + return (srs_amf0_t)obj->get_property(name); | ||
| 740 | +} | ||
| 741 | + | ||
| 742 | +void srs_amf0_ecma_array_property_set(srs_amf0_t amf0, const char* name, srs_amf0_t value) | ||
| 743 | +{ | ||
| 744 | + SrsAmf0EcmaArray* obj = (SrsAmf0EcmaArray*)amf0; | ||
| 745 | + SrsAmf0Any* any = (SrsAmf0Any*)value; | ||
| 746 | + obj->set(name, any); | ||
| 747 | +} | ||
| 748 | + | ||
| 646 | int srs_amf0_strict_array_property_count(srs_amf0_t amf0) | 749 | int srs_amf0_strict_array_property_count(srs_amf0_t amf0) |
| 647 | { | 750 | { |
| 648 | - SrsAmf0EcmaArray * obj = (SrsAmf0EcmaArray*)amf0; | 751 | + SrsAmf0StrictArray * obj = (SrsAmf0StrictArray*)amf0; |
| 649 | return obj->count(); | 752 | return obj->count(); |
| 650 | } | 753 | } |
| 651 | 754 | ||
| 652 | srs_amf0_t srs_amf0_strict_array_property_at(srs_amf0_t amf0, int index) | 755 | srs_amf0_t srs_amf0_strict_array_property_at(srs_amf0_t amf0, int index) |
| 653 | { | 756 | { |
| 654 | - SrsAmf0EcmaArray* obj = (SrsAmf0EcmaArray*)amf0; | ||
| 655 | - return (srs_amf0_t)obj->value_at(index); | 757 | + SrsAmf0StrictArray* obj = (SrsAmf0StrictArray*)amf0; |
| 758 | + return (srs_amf0_t)obj->at(index); | ||
| 759 | +} | ||
| 760 | + | ||
| 761 | +void srs_amf0_strict_array_append(srs_amf0_t amf0, srs_amf0_t value) | ||
| 762 | +{ | ||
| 763 | + SrsAmf0StrictArray* obj = (SrsAmf0StrictArray*)amf0; | ||
| 764 | + SrsAmf0Any* any = (SrsAmf0Any*)value; | ||
| 765 | + obj->append(any); | ||
| 656 | } | 766 | } |
| 657 | 767 | ||
| 658 | void __srs_fill_level_spaces(stringstream& ss, int level) | 768 | 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) | @@ -735,10 +845,14 @@ char* srs_amf0_human_print(srs_amf0_t amf0, char** pdata, int* psize) | ||
| 735 | memcpy(data, str.data(), str.length()); | 845 | memcpy(data, str.data(), str.length()); |
| 736 | data[str.length()] = 0; | 846 | data[str.length()] = 0; |
| 737 | 847 | ||
| 738 | - *pdata = data; | ||
| 739 | - *psize = str.length(); | 848 | + if (pdata) { |
| 849 | + *pdata = data; | ||
| 850 | + } | ||
| 851 | + if (psize) { | ||
| 852 | + *psize = str.length(); | ||
| 853 | + } | ||
| 740 | 854 | ||
| 741 | - return *pdata; | 855 | + return data; |
| 742 | } | 856 | } |
| 743 | 857 | ||
| 744 | #ifdef __cplusplus | 858 | #ifdef __cplusplus |
| @@ -165,12 +165,23 @@ int srs_flv_read_header(srs_flv_t flv, char header[9]); | @@ -165,12 +165,23 @@ int srs_flv_read_header(srs_flv_t flv, char header[9]); | ||
| 165 | int srs_flv_read_tag_header(srs_flv_t flv, char* ptype, int32_t* pdata_size, u_int32_t* ptime); | 165 | int srs_flv_read_tag_header(srs_flv_t flv, char* ptype, int32_t* pdata_size, u_int32_t* ptime); |
| 166 | /* read the tag data. drop the 4bytes previous tag size */ | 166 | /* read the tag data. drop the 4bytes previous tag size */ |
| 167 | int srs_flv_read_tag_data(srs_flv_t flv, char* data, int32_t size); | 167 | int srs_flv_read_tag_data(srs_flv_t flv, char* data, int32_t size); |
| 168 | +/* write flv header to file, auto write the 4bytes zero previous tag size. */ | ||
| 169 | +int srs_flv_write_header(srs_flv_t flv, char header[9]); | ||
| 170 | +/* write flv tag to file, auto write the 4bytes previous tag size */ | ||
| 171 | +int srs_flv_write_tag(srs_flv_t flv, char type, int32_t time, char* data, int size); | ||
| 172 | +/* file stream */ | ||
| 168 | /* file stream tellg to get offset */ | 173 | /* file stream tellg to get offset */ |
| 169 | int64_t srs_flv_tellg(srs_flv_t flv); | 174 | int64_t srs_flv_tellg(srs_flv_t flv); |
| 170 | /* seek file stream, offset is form the start of file */ | 175 | /* seek file stream, offset is form the start of file */ |
| 171 | void srs_flv_lseek(srs_flv_t flv, int64_t offset); | 176 | void srs_flv_lseek(srs_flv_t flv, int64_t offset); |
| 177 | +/* error code */ | ||
| 172 | /* whether the error code indicates EOF */ | 178 | /* whether the error code indicates EOF */ |
| 173 | flv_bool srs_flv_is_eof(int error_code); | 179 | flv_bool srs_flv_is_eof(int error_code); |
| 180 | +/* media codec */ | ||
| 181 | +/* whether the video body is sequence header */ | ||
| 182 | +flv_bool srs_flv_is_sequence_header(char* data, int32_t size); | ||
| 183 | +/* whether the video body is keyframe */ | ||
| 184 | +flv_bool srs_flv_is_keyframe(char* data, int32_t size); | ||
| 174 | 185 | ||
| 175 | /** | 186 | /** |
| 176 | * amf0 codec | 187 | * amf0 codec |
| @@ -180,8 +191,14 @@ typedef void* srs_amf0_t; | @@ -180,8 +191,14 @@ typedef void* srs_amf0_t; | ||
| 180 | typedef int amf0_bool; | 191 | typedef int amf0_bool; |
| 181 | typedef double amf0_number; | 192 | typedef double amf0_number; |
| 182 | srs_amf0_t srs_amf0_parse(char* data, int size, int* nparsed); | 193 | srs_amf0_t srs_amf0_parse(char* data, int size, int* nparsed); |
| 194 | +srs_amf0_t srs_amf0_create_number(amf0_number value); | ||
| 195 | +srs_amf0_t srs_amf0_create_ecma_array(); | ||
| 196 | +srs_amf0_t srs_amf0_create_strict_array(); | ||
| 183 | void srs_amf0_free(srs_amf0_t amf0); | 197 | void srs_amf0_free(srs_amf0_t amf0); |
| 184 | void srs_amf0_free_bytes(char* data); | 198 | void srs_amf0_free_bytes(char* data); |
| 199 | +/* size and to bytes */ | ||
| 200 | +int srs_amf0_size(srs_amf0_t amf0); | ||
| 201 | +int srs_amf0_serialize(srs_amf0_t amf0, char* data, int size); | ||
| 185 | /* type detecter */ | 202 | /* type detecter */ |
| 186 | amf0_bool srs_amf0_is_string(srs_amf0_t amf0); | 203 | amf0_bool srs_amf0_is_string(srs_amf0_t amf0); |
| 187 | amf0_bool srs_amf0_is_boolean(srs_amf0_t amf0); | 204 | amf0_bool srs_amf0_is_boolean(srs_amf0_t amf0); |
| @@ -198,13 +215,18 @@ amf0_number srs_amf0_to_number(srs_amf0_t amf0); | @@ -198,13 +215,18 @@ amf0_number srs_amf0_to_number(srs_amf0_t amf0); | ||
| 198 | int srs_amf0_object_property_count(srs_amf0_t amf0); | 215 | int srs_amf0_object_property_count(srs_amf0_t amf0); |
| 199 | const char* srs_amf0_object_property_name_at(srs_amf0_t amf0, int index); | 216 | const char* srs_amf0_object_property_name_at(srs_amf0_t amf0, int index); |
| 200 | srs_amf0_t srs_amf0_object_property_value_at(srs_amf0_t amf0, int index); | 217 | srs_amf0_t srs_amf0_object_property_value_at(srs_amf0_t amf0, int index); |
| 218 | +srs_amf0_t srs_amf0_object_property(srs_amf0_t amf0, const char* name); | ||
| 219 | +void srs_amf0_object_property_set(srs_amf0_t amf0, const char* name, srs_amf0_t value); | ||
| 201 | /* ecma array value converter */ | 220 | /* ecma array value converter */ |
| 202 | int srs_amf0_ecma_array_property_count(srs_amf0_t amf0); | 221 | int srs_amf0_ecma_array_property_count(srs_amf0_t amf0); |
| 203 | const char* srs_amf0_ecma_array_property_name_at(srs_amf0_t amf0, int index); | 222 | const char* srs_amf0_ecma_array_property_name_at(srs_amf0_t amf0, int index); |
| 204 | srs_amf0_t srs_amf0_ecma_array_property_value_at(srs_amf0_t amf0, int index); | 223 | srs_amf0_t srs_amf0_ecma_array_property_value_at(srs_amf0_t amf0, int index); |
| 224 | +srs_amf0_t srs_amf0_ecma_array_property(srs_amf0_t amf0, const char* name); | ||
| 225 | +void srs_amf0_ecma_array_property_set(srs_amf0_t amf0, const char* name, srs_amf0_t value); | ||
| 205 | /* strict array value converter */ | 226 | /* strict array value converter */ |
| 206 | int srs_amf0_strict_array_property_count(srs_amf0_t amf0); | 227 | int srs_amf0_strict_array_property_count(srs_amf0_t amf0); |
| 207 | srs_amf0_t srs_amf0_strict_array_property_at(srs_amf0_t amf0, int index); | 228 | srs_amf0_t srs_amf0_strict_array_property_at(srs_amf0_t amf0, int index); |
| 229 | +void srs_amf0_strict_array_append(srs_amf0_t amf0, srs_amf0_t value); | ||
| 208 | /** | 230 | /** |
| 209 | * human readable print | 231 | * human readable print |
| 210 | * @param pdata, output the heap data, | 232 | * @param pdata, output the heap data, |
| @@ -1113,6 +1113,11 @@ SrsAmf0Any* SrsAmf0StrictArray::at(int index) | @@ -1113,6 +1113,11 @@ SrsAmf0Any* SrsAmf0StrictArray::at(int index) | ||
| 1113 | return properties.at(index); | 1113 | return properties.at(index); |
| 1114 | } | 1114 | } |
| 1115 | 1115 | ||
| 1116 | +void SrsAmf0StrictArray::append(SrsAmf0Any* any) | ||
| 1117 | +{ | ||
| 1118 | + properties.push_back(any); | ||
| 1119 | +} | ||
| 1120 | + | ||
| 1116 | int SrsAmf0Size::utf8(string value) | 1121 | int SrsAmf0Size::utf8(string value) |
| 1117 | { | 1122 | { |
| 1118 | return 2 + value.length(); | 1123 | return 2 + value.length(); |
| @@ -260,6 +260,7 @@ public: | @@ -260,6 +260,7 @@ public: | ||
| 260 | virtual int count(); | 260 | virtual int count(); |
| 261 | // @remark: max index is count(). | 261 | // @remark: max index is count(). |
| 262 | virtual SrsAmf0Any* at(int index); | 262 | virtual SrsAmf0Any* at(int index); |
| 263 | + virtual void append(SrsAmf0Any* any); | ||
| 263 | }; | 264 | }; |
| 264 | 265 | ||
| 265 | /** | 266 | /** |
-
请 注册 或 登录 后发表评论