int SrsHttpVhost::response_ts_file(SrsStSocket* skt, SrsHttpMessage* req, string fullpath) { int ret = ERROR_SUCCESS; SrsFileReader fs; // TODO: FIXME: use more advance cache. if ((ret = fs.open(fullpath)) != ERROR_SUCCESS) { srs_warn("open file %s failed, ret=%d", fullpath.c_str(), ret); return ret; } int64_t length = fs.filesize(); // write http header for ts. std::stringstream ss; res_status_line(ss)->res_content_type_mpegts(ss) ->res_content_length(ss, (int)length); if (req->requires_crossdomain()) { res_enable_crossdomain(ss); } res_header_eof(ss); // flush http header to peer if ((ret = res_flush(skt, ss)) != ERROR_SUCCESS) { return ret; } // write body. int64_t left = length; char* buf = req->http_ts_send_buffer(); while (left > 0) { ssize_t nread = -1; if ((ret = fs.read(buf, __SRS_HTTP_TS_SEND_BUFFER_SIZE, &nread)) != ERROR_SUCCESS) { srs_warn("read file %s failed, ret=%d", fullpath.c_str(), ret); break; } left -= nread; if ((ret = skt->write(buf, nread, NULL)) != ERROR_SUCCESS) { break; } } return ret; }
int SrsHttpVhost::response_regular_file(SrsStSocket* skt, SrsHttpMessage* req, string fullpath) { int ret = ERROR_SUCCESS; SrsFileReader fs; if ((ret = fs.open(fullpath)) != ERROR_SUCCESS) { srs_warn("open file %s failed, ret=%d", fullpath.c_str(), ret); return ret; } int64_t length = fs.filesize(); char* buf = new char[length]; SrsAutoFree(char, buf); if ((ret = fs.read(buf, length, NULL)) != ERROR_SUCCESS) { srs_warn("read file %s failed, ret=%d", fullpath.c_str(), ret); return ret; } std::string str; str.append(buf, length); if (srs_string_ends_with(fullpath, ".ts")) { return res_mpegts(skt, req, str); } else if (srs_string_ends_with(fullpath, ".m3u8")) { return res_m3u8(skt, req, str); } else if (srs_string_ends_with(fullpath, ".xml")) { return res_xml(skt, req, str); } else if (srs_string_ends_with(fullpath, ".js")) { return res_javascript(skt, req, str); } else if (srs_string_ends_with(fullpath, ".json")) { return res_json(skt, req, str); } else if (srs_string_ends_with(fullpath, ".swf")) { return res_swf(skt, req, str); } else if (srs_string_ends_with(fullpath, ".css")) { return res_css(skt, req, str); } else if (srs_string_ends_with(fullpath, ".ico")) { return res_ico(skt, req, str); } else { return res_text(skt, req, str); } return ret; }
int SrsVodStream::serve_mp4_stream(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, string fullpath, int start, int end) { int ret = ERROR_SUCCESS; srs_assert(start >= 0); srs_assert(end == -1 || end >= 0); SrsFileReader fs; // open flv file if ((ret = fs.open(fullpath)) != ERROR_SUCCESS) { return ret; } // parse -1 to whole file. if (end == -1) { end = (int)fs.filesize(); } if (end > fs.filesize() || start > end) { ret = ERROR_HTTP_REMUX_OFFSET_OVERFLOW; srs_warn("http mp4 streaming %s overflow. size=%"PRId64", offset=%d, ret=%d", fullpath.c_str(), fs.filesize(), start, ret); return ret; } // seek to data offset, [start, end] for range. int64_t left = end - start + 1; // write http header for ts. w->header()->set_content_length(left); w->header()->set_content_type("video/mp4"); // status code 206 to make dash.as happy. w->write_header(SRS_CONSTS_HTTP_PartialContent); // response the content range header. std::stringstream content_range; content_range << "bytes " << start << "-" << end << "/" << fs.filesize(); w->header()->set("Content-Range", content_range.str()); // write body. fs.lseek(start); // send data if ((ret = copy(w, &fs, r, (int)left)) != ERROR_SUCCESS) { srs_warn("read mp4=%s size=%d failed, ret=%d", fullpath.c_str(), left, ret); return ret; } return ret; }
int SrsHttpVhost::response_flv_file2(SrsStSocket* skt, SrsHttpMessage* req, string fullpath, int offset) { int ret = ERROR_SUCCESS; SrsFileReader fs; // open flv file if ((ret = fs.open(fullpath)) != ERROR_SUCCESS) { return ret; } if (offset > fs.filesize()) { ret = ERROR_HTTP_FLV_OFFSET_OVERFLOW; srs_warn("http flv streaming %s overflow. size=%"PRId64", offset=%d, ret=%d", fullpath.c_str(), fs.filesize(), offset, ret); return ret; } SrsFlvVodStreamDecoder ffd; // open fast decoder if ((ret = ffd.initialize(&fs)) != ERROR_SUCCESS) { return ret; } // save header, send later. char flv_header[13]; // send flv header if ((ret = ffd.read_header_ext(flv_header)) != ERROR_SUCCESS) { return ret; } // save sequence header, send later char* sh_data = NULL; int sh_size = 0; if (true) { // send sequence header int64_t start = 0; if ((ret = ffd.read_sequence_header_summary(&start, &sh_size)) != ERROR_SUCCESS) { return ret; } if (sh_size <= 0) { ret = ERROR_HTTP_FLV_SEQUENCE_HEADER; srs_warn("http flv streaming no sequence header. size=%d, ret=%d", sh_size, ret); return ret; } } sh_data = new char[sh_size]; SrsAutoFree(char, sh_data); if ((ret = fs.read(sh_data, sh_size, NULL)) != ERROR_SUCCESS) { return ret; } // seek to data offset int64_t left = fs.filesize() - offset; // write http header for ts. std::stringstream ss; res_status_line(ss)->res_content_type_flv(ss) ->res_content_length(ss, (int)(sizeof(flv_header) + sh_size + left)); if (req->requires_crossdomain()) { res_enable_crossdomain(ss); } res_header_eof(ss); // flush http header to peer if ((ret = res_flush(skt, ss)) != ERROR_SUCCESS) { return ret; } if ((ret = skt->write(flv_header, sizeof(flv_header), NULL)) != ERROR_SUCCESS) { return ret; } if (sh_size > 0 && (ret = skt->write(sh_data, sh_size, NULL)) != ERROR_SUCCESS) { return ret; } // write body. char* buf = req->http_ts_send_buffer(); if ((ret = ffd.lseek(offset)) != ERROR_SUCCESS) { return ret; } // send data while (left > 0) { ssize_t nread = -1; if ((ret = fs.read(buf, __SRS_HTTP_TS_SEND_BUFFER_SIZE, &nread)) != ERROR_SUCCESS) { return ret; } left -= nread; if ((ret = skt->write(buf, nread, NULL)) != ERROR_SUCCESS) { return ret; } } return ret; }
int SrsVodStream::serve_flv_stream(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, string fullpath, int offset) { int ret = ERROR_SUCCESS; SrsFileReader fs; // open flv file if ((ret = fs.open(fullpath)) != ERROR_SUCCESS) { return ret; } if (offset > fs.filesize()) { ret = ERROR_HTTP_REMUX_OFFSET_OVERFLOW; srs_warn("http flv streaming %s overflow. size=%"PRId64", offset=%d, ret=%d", fullpath.c_str(), fs.filesize(), offset, ret); return ret; } SrsFlvVodStreamDecoder ffd; // open fast decoder if ((ret = ffd.initialize(&fs)) != ERROR_SUCCESS) { return ret; } // save header, send later. char flv_header[13]; // send flv header if ((ret = ffd.read_header_ext(flv_header)) != ERROR_SUCCESS) { return ret; } // save sequence header, send later char* sh_data = NULL; int sh_size = 0; if (true) { // send sequence header int64_t start = 0; if ((ret = ffd.read_sequence_header_summary(&start, &sh_size)) != ERROR_SUCCESS) { return ret; } if (sh_size <= 0) { ret = ERROR_HTTP_REMUX_SEQUENCE_HEADER; srs_warn("http flv streaming no sequence header. size=%d, ret=%d", sh_size, ret); return ret; } } sh_data = new char[sh_size]; SrsAutoFreeA(char, sh_data); if ((ret = fs.read(sh_data, sh_size, NULL)) != ERROR_SUCCESS) { return ret; } // seek to data offset int64_t left = fs.filesize() - offset; // write http header for ts. w->header()->set_content_length((int)(sizeof(flv_header) + sh_size + left)); w->header()->set_content_type("video/x-flv"); // write flv header and sequence header. if ((ret = w->write(flv_header, sizeof(flv_header))) != ERROR_SUCCESS) { return ret; } if (sh_size > 0 && (ret = w->write(sh_data, sh_size)) != ERROR_SUCCESS) { return ret; } // write body. if ((ret = ffd.lseek(offset)) != ERROR_SUCCESS) { return ret; } // send data if ((ret = copy(w, &fs, r, (int)left)) != ERROR_SUCCESS) { srs_warn("read flv=%s size=%d failed, ret=%d", fullpath.c_str(), left, ret); return ret; } return ret; }