|
- #include "mpeg4-aac.h"
- #include "mpeg4-avc.h"
- #include "mpeg4-hevc.h"
- #include "flv-muxer.h"
- #include "flv-writer.h"
- #include "http-server.h"
- #include "aio-worker.h"
- #include "uri-parse.h"
- #include "urlcodec.h"
- #include "sys/thread.h"
- #include "sys/system.h"
- #include "sys/path.h"
- #include "cstringext.h"
- #include <stdio.h>
- #include "utf8codec.h"
- #include "../deprecated/StdCFile.h"
- #include "cpm/shared_ptr.h"
- #include <vector>
-
- #define CWD "."
-
- struct http_flv_live_t
- {
- char path[PATH_MAX];
- std::shared_ptr<uint8_t> buf;
- size_t cap;
- size_t len;
-
- http_session_t* http;
- std::shared_ptr<void> writer;
- std::shared_ptr<flv_muxer_t> muxer;
- uint32_t pts, dts;
-
- std::shared_ptr<void> content;
- std::vector<std::pair<const uint8_t*, int> > frames; // h264 frames
- std::vector<std::pair<const uint8_t*, int> >::const_iterator it;
- const uint8_t* ptr;
- int vcl;
- };
-
- static int http_flv_live_read(http_flv_live_t* live);
- static int http_flv_live_send(http_flv_live_t* live);
-
- static int http_flv_live_destroy(http_flv_live_t* live)
- {
- // TODO: close http sessoin
- delete live;
- return 0;
- }
-
- static int http_flv_live_onsend(void* param, int code, size_t bytes)
- {
- http_flv_live_t* live = (http_flv_live_t*)param;
- if (0 != code)
- {
- printf("===============send error: %d===============\r\n", code);
- http_flv_live_destroy(live);
- return 0;
- }
-
- assert(live->len = bytes);
- live->len = 0; // clear
-
- system_sleep(40); // next frame
-
- return http_flv_live_send(live);
- }
-
- static int http_flv_live_send(http_flv_live_t* live)
- {
- if (live->it == live->frames.end())
- {
- printf("===============done===============\r\n");
- http_flv_live_destroy(live);
- return 0; /*end*/
- }
-
- int r = flv_muxer_avc(live->muxer.get(), live->it->first, live->it->second, live->pts, live->dts);
- live->pts += 40;
- live->dts += 40;
- live->it++;
-
- if (0 != r)
- {
- printf("===============send error===============\r\n");
- http_flv_live_destroy(live);
- return r;
- }
-
- r = http_server_send(live->http, live->buf.get(), live->len, http_flv_live_onsend, live);
- return 0 == r ? 1 /*more data*/ : r;
- }
-
- static int http_flv_write(void* param, const struct flv_vec_t* v, int n)
- {
- http_flv_live_t* live = (http_flv_live_t*)param;
-
- assert(n <= 3);
- for (int i = 0; i < n; i++)
- {
- if (live->len + v[i].len > live->cap)
- {
- // TODO: realloc
- assert(0);
- return -1;
- }
-
- // TODO: avoid memory copy
- memcpy(live->buf.get() + live->len, v[i].ptr, v[i].len);
- live->len += v[i].len;
- }
- return 0;
- }
-
- static int http_flv_muxer_handler(void* param, int type, const void* data, size_t bytes, uint32_t timestamp)
- {
- http_flv_live_t* live = (http_flv_live_t*)param;
- return flv_writer_input(live->writer.get(), type, data, bytes, timestamp);
- }
-
- static int http_flv_live(void* http, http_session_t* session, const char* method, const char* path)
- {
- char buffer[1024];//[PATH_MAX];
- http_flv_live_t* live = new http_flv_live_t();
-
- struct uri_t* uri = uri_parse(path, (int)strlen(path));
- url_decode(uri->path, -1, live->path, sizeof(live->path));
- uri_free(uri);
-
- int n = 0;
- while (live->path[n] == '/') n++; // filter /
- UTF8Decode utf8(live->path+n);
-
- path_resolve(buffer, sizeof(buffer), utf8, CWD, strlen(CWD));
- // TODO: path resolve to fix /rootpath/../pathtosystem -> /pathtosystem
- path_realpath(buffer, live->path);
-
- // read frames
- int r = http_flv_live_read(live);
- if (0 != r)
- {
- delete live;
- http_server_set_status_code(session, r, NULL);
- return http_server_send(session, "", 0, NULL, NULL);
- }
-
- live->http = session;
- http_server_set_header(session, "Connection", "close"); // server close connection on finish
- http_server_set_content_length(session, -1); // don't need content-length
-
- live->pts = 0;
- live->dts = 0;
- live->it = live->frames.begin();
- live->muxer.reset(flv_muxer_create(http_flv_muxer_handler, live), flv_muxer_destroy);
-
- // write flv file header
- live->writer.reset(flv_writer_create2(0, 1, http_flv_write, live), flv_writer_destroy);
- return http_flv_live_send(live);
- }
-
- void http_flv_live_test(const char* ip, int port)
- {
- aio_worker_init(4);
- http_server_t* http = http_server_create(ip, port);
- http_server_set_handler(http, http_flv_live, http);
-
- // http process
- while ('q' != getchar())
- {
- }
-
- http_server_destroy(http);
- aio_worker_clean(4);
- }
-
- static void h264_handler(void* param, const uint8_t* nalu, size_t bytes)
- {
- http_flv_live_t* ctx = (http_flv_live_t*)param;
- assert(ctx->ptr < nalu);
-
- const uint8_t* ptr = nalu - 3;
- //const uint8_t* end = (const uint8_t*)nalu + bytes;
- uint8_t nalutype = nalu[0] & 0x1f;
- if (ctx->vcl > 0 && h264_is_new_access_unit(nalu, bytes))
- {
- ctx->cap = ptr - ctx->ptr > ctx->cap ? ptr - ctx->ptr : ctx->cap; // max
- ctx->frames.push_back(std::make_pair(ctx->ptr, ptr - ctx->ptr));
- ctx->ptr = ptr;
- ctx->vcl = 0;
- }
-
- if (1 <= nalutype && nalutype <= 5)
- ++ctx->vcl;
- }
-
- static int http_flv_live_read(http_flv_live_t* live)
- {
- StdCFile fp(live->path, "rb");
- if (!fp.IsOpened())
- return 404;
-
- long n = fp.GetFileSize();
- if (n >= 32 * 1024 * 1024)
- return 401;
-
- live->content.reset(fp.Read(), free);
- if (!live->content.get())
- return 500;
-
- live->vcl = 0;
- live->ptr = (const uint8_t*)live->content.get();
- live->cap = 0;
- live->len = 0;
-
- if (strendswith(live->path, ".h264") || strendswith(live->path, ".264"))
- {
- mpeg4_h264_annexb_nalu(live->content.get(), n, h264_handler, live);
-
- live->cap += 4 * 1024; // flv avc/aac sequence header
- live->buf.reset((uint8_t*)malloc(live->cap), free);
- }
- else
- {
- return 500;
- }
-
- return 0;
- }
|