winlin

supprt inject flv

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, &timestamp)) != 0) { 184 + if ((ret = srs_flv_read_tag_header(ic, &type, &size, &timestamp)) != 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, &timestamp)) != 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, &timestamp); 173 + ret = do_proxy(flv, ortmp, re, &timestamp);
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 /**