1
0
Fork 0
mirror of https://github.com/ossrs/srs.git synced 2025-03-09 15:49:59 +00:00

supprt inject flv

This commit is contained in:
winlin 2014-05-28 19:01:47 +08:00
parent 4970664e37
commit 22968c85df
10 changed files with 313 additions and 184 deletions

View file

@ -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 <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#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

View file

@ -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, &timestamp)) != 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, &timestamp)) != 0) {
if ((ret = srs_flv_read_tag_header(ic, &type, &size, &timestamp)) != 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);

View file

@ -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)

View file

@ -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, &timestamp);
ret = do_proxy(flv, ortmp, re, &timestamp);
// for the last pulse, always sleep.
re_cleanup(re, timestamp);