mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
Merge branch '3.0release' into develop
This commit is contained in:
commit
1794f805ec
14 changed files with 320 additions and 148 deletions
26
.github/ISSUE_TEMPLATE
vendored
26
.github/ISSUE_TEMPLATE
vendored
|
@ -9,15 +9,9 @@ assignees: ''
|
|||
|
||||
**描述(Description)**
|
||||
|
||||
描述你遇到了什么问题。
|
||||
(Please description your issue here.)
|
||||
|
||||
**环境(Environment)**
|
||||
> 描述你遇到了什么问题(Please description your issue here)
|
||||
|
||||
1. SRS版本(Version): `xxxxxx`
|
||||
1. 操作系统(OS):`xxxxxx`
|
||||
1. 编码器(工具和版本)(Encoder):`xxxxxx`
|
||||
1. 播放器(工具和版本)(Player):`xxxxxx`
|
||||
1. SRS的日志如下(Log):
|
||||
```
|
||||
xxxxxxxxxxxx
|
||||
|
@ -25,20 +19,12 @@ xxxxxxxxxxxx
|
|||
|
||||
**重现(Replay)**
|
||||
|
||||
重现Bug的步骤如下:
|
||||
(How to replay bug?)
|
||||
> 重现Bug的步骤(How to replay bug?)
|
||||
|
||||
1. 启动SRS,运行(Start SRS by) `xxxxxx`
|
||||
1. 推流,运行(Publish by) `xxxxxx`
|
||||
1. 播放,运行(Play by) `xxxxxx`
|
||||
1. 操作(Other steps) `xxxxxx`
|
||||
1. 重现了Bug,关键信息如下(Bug replayed, logs):
|
||||
|
||||
```
|
||||
xxxxxx
|
||||
```
|
||||
1. `xxxxxx`
|
||||
1. `xxxxxx`
|
||||
1. `xxxxxx`
|
||||
|
||||
**期望行为(Expect)**
|
||||
|
||||
描述你期望发生的事情。
|
||||
(Please describe your expectation.)
|
||||
> 描述你期望发生的事情(Please describe your expectation)
|
||||
|
|
|
@ -148,6 +148,11 @@ For previous versions, please read:
|
|||
|
||||
## V3 changes
|
||||
|
||||
* v3.0, 2019-12-27, For [#299][bug #299], fix some bugs in dash, it works now. 3.0.88
|
||||
* v3.0, 2019-12-27, For [#1544][bug #1544], fix memory leaking for complex error. 3.0.87
|
||||
* v3.0, 2019-12-27, Add links for flv.js, hls.js and dash.js.
|
||||
* v3.0, 2019-12-26, For [#1105][bug #1105], http server support mp4 range.
|
||||
* v3.0, 2019-12-26, For [#1105][bug #1105], dvr mp4 supports playing on Chrome/Safari/Firefox. 3.0.86
|
||||
* <strong>v3.0, 2019-12-26, [3.0 alpha6(3.0.85)][r3.0a6] released. 116056 lines.</strong>
|
||||
* v3.0, 2019-12-26, For [#1488][bug #1488], pass client ip to http callback. 3.0.85
|
||||
* v3.0, 2019-12-25, For [#1537][bug #1537], [#1282][bug #1282], support aarch64 for armv8. 3.0.84
|
||||
|
@ -1567,6 +1572,8 @@ Winlin
|
|||
[bug #1537]: https://github.com/ossrs/srs/issues/1537
|
||||
[bug #1538]: https://github.com/ossrs/srs/issues/1538
|
||||
[bug #1282]: https://github.com/ossrs/srs/issues/1282
|
||||
[bug #1105]: https://github.com/ossrs/srs/issues/1105
|
||||
[bug #1544]: https://github.com/ossrs/srs/issues/1544
|
||||
[bug #xxxxxxxxxxxxx]: https://github.com/ossrs/srs/issues/xxxxxxxxxxxxx
|
||||
|
||||
[bug #1111]: https://github.com/ossrs/srs/issues/1111
|
||||
|
|
|
@ -9,56 +9,30 @@
|
|||
padding-top: 55px;
|
||||
}
|
||||
</style>
|
||||
<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
|
||||
<script type="text/javascript" src="js/bootstrap.min.js"></script>
|
||||
<script type="text/javascript" src="js/swfobject.js"></script>
|
||||
<script type="text/javascript" src="js/srs.page.js"></script>
|
||||
<script type="text/javascript" src="js/srs.utility.js"></script>
|
||||
<script type="text/javascript" src="js/winlin.utility.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(function(){
|
||||
update_nav();
|
||||
|
||||
var query = parse_query_string();
|
||||
var url = "srs_player.html?vhost=" + srs_get_player_vhost();
|
||||
|
||||
for (var key in query.user_query) {
|
||||
if (key == "vhost") {
|
||||
continue;
|
||||
}
|
||||
url += "&" + key + "=" + query[key];
|
||||
}
|
||||
|
||||
window.location.href = url;
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="navbar navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container">
|
||||
<a id="srs_index" class="brand" href="#">SRS</a>
|
||||
<div class="nav-collapse collapse">
|
||||
<ul class="nav">
|
||||
<li><a id="nav_srs_player" href="srs_player.html">SRS播放器</a></li>
|
||||
<li><a id="nav_srs_publisher" href="srs_publisher.html">SRS编码器</a></li>
|
||||
<li><a id="nav_srs_chat" href="srs_chat.html">SRS会议</a></li>
|
||||
<li><a id="nav_srs_bwt" href="srs_bwt.html">SRS测网速</a></li>
|
||||
<li><a id="nav_jwplayer6" href="jwplayer6.html">JWPlayer6播放器</a></li>
|
||||
<li><a id="nav_osmf" href="osmf.html">AdobeOSMF播放器</a></li>
|
||||
<li><a id="nav_vlc" href="vlc.html">VLC播放器</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
<hr>
|
||||
<footer>
|
||||
<p><a href="https://github.com/ossrs/srs">SRS Team © 2013</a></p>
|
||||
</footer>
|
||||
</div>
|
||||
<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
|
||||
<script type="text/javascript" src="js/bootstrap.min.js"></script>
|
||||
<script type="text/javascript" src="js/swfobject.js"></script>
|
||||
<script type="text/javascript" src="js/srs.page.js"></script>
|
||||
<script type="text/javascript" src="js/srs.utility.js"></script>
|
||||
<script type="text/javascript" src="js/winlin.utility.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(function(){
|
||||
update_nav();
|
||||
|
||||
var query = parse_query_string();
|
||||
var url = "srs_chat.html?vhost=" + srs_get_player_vhost();
|
||||
|
||||
for (var key in query.user_query) {
|
||||
if (key == "vhost") {
|
||||
continue;
|
||||
}
|
||||
url += "&" + key + "=" + query[key];
|
||||
}
|
||||
|
||||
setTimeout(function(){
|
||||
window.location.href = url;
|
||||
}, 100);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
|
|
|
@ -71,6 +71,15 @@
|
|||
<input type="text" id="txt_url" class="input-xxlarge" value="">
|
||||
<button class="btn btn-primary" id="btn_play">播放视频</button>
|
||||
<button class="btn" id="btn_generate_link">生成链接</button>
|
||||
<p></p>
|
||||
<p>
|
||||
推荐的其他播放器:
|
||||
<ul>
|
||||
<li><a href="http://bilibili.github.io/flv.js/demo">flv.js</a>,H5/MSE播放HTTP-FLV</li>
|
||||
<li><a href="https://hls-js.netlify.com/demo">hls.js</a>,H5/MSE播放HLS</li>
|
||||
<li><a href="http://reference.dashif.org/dash.js/nightly/samples/dash-if-reference-player/index.html">dash.js</a>,H5/MSE播放MPEG-DASH</li>
|
||||
</ul>
|
||||
</p>
|
||||
</div>
|
||||
<div id="link_modal" class="modal hide fade">
|
||||
<div class="modal-header">
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include <srs_core_autofree.hpp>
|
||||
#include <srs_kernel_mp4.hpp>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sstream>
|
||||
using namespace std;
|
||||
|
||||
|
@ -276,10 +277,17 @@ srs_error_t SrsMpdWriter::get_fragment(bool video, std::string& home, std::strin
|
|||
srs_error_t err = srs_success;
|
||||
|
||||
home = fragment_home;
|
||||
|
||||
sn = srs_update_system_time() / fragment;
|
||||
|
||||
// We name the segment as advanced N segments, because when we are generating segment at the current time,
|
||||
// the player may also request the current segment.
|
||||
srs_assert(fragment);
|
||||
int64_t number = (srs_update_system_time() / fragment + 1);
|
||||
// TOOD: FIXME: Should keep the segments continuous, or player may fail.
|
||||
sn = number;
|
||||
|
||||
// The base time aligned with sn.
|
||||
basetime = sn * fragment;
|
||||
|
||||
|
||||
if (video) {
|
||||
file_name = "video-" + srs_int2str(sn) + ".m4s";
|
||||
} else {
|
||||
|
@ -292,7 +300,7 @@ srs_error_t SrsMpdWriter::get_fragment(bool video, std::string& home, std::strin
|
|||
SrsDashController::SrsDashController()
|
||||
{
|
||||
req = NULL;
|
||||
video_tack_id = 2;
|
||||
video_tack_id = 0;
|
||||
audio_track_id = 1;
|
||||
mpd = new SrsMpdWriter();
|
||||
vcurrent = acurrent = NULL;
|
||||
|
@ -332,6 +340,10 @@ srs_error_t SrsDashController::on_publish()
|
|||
fragment = _srs_config->get_dash_fragment(r->vhost);
|
||||
home = _srs_config->get_dash_path(r->vhost);
|
||||
|
||||
if ((err = mpd->on_publish()) != srs_success) {
|
||||
return srs_error_wrap(err, "mpd");
|
||||
}
|
||||
|
||||
srs_freep(vcurrent);
|
||||
vcurrent = new SrsFragmentedMp4();
|
||||
if ((err = vcurrent->initialize(req, true, mpd, video_tack_id)) != srs_success) {
|
||||
|
@ -344,10 +356,6 @@ srs_error_t SrsDashController::on_publish()
|
|||
return srs_error_wrap(err, "audio fragment");
|
||||
}
|
||||
|
||||
if ((err = mpd->on_publish()) != srs_success) {
|
||||
return srs_error_wrap(err, "mpd");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
@ -489,7 +489,7 @@ srs_error_t SrsDvrMp4Segmenter::encode_audio(SrsSharedPtrMessage* audio, SrsForm
|
|||
uint32_t nb_sample = (uint32_t)format->nb_raw;
|
||||
|
||||
uint32_t dts = (uint32_t)audio->timestamp;
|
||||
if ((err = enc->write_sample(SrsMp4HandlerTypeSOUN, 0x00, ct, dts, dts, sample, nb_sample)) != srs_success) {
|
||||
if ((err = enc->write_sample(format, SrsMp4HandlerTypeSOUN, 0x00, ct, dts, dts, sample, nb_sample)) != srs_success) {
|
||||
return srs_error_wrap(err, "write sample");
|
||||
}
|
||||
|
||||
|
@ -515,7 +515,7 @@ srs_error_t SrsDvrMp4Segmenter::encode_video(SrsSharedPtrMessage* video, SrsForm
|
|||
|
||||
uint8_t* sample = (uint8_t*)format->raw;
|
||||
uint32_t nb_sample = (uint32_t)format->nb_raw;
|
||||
if ((err = enc->write_sample(SrsMp4HandlerTypeVIDE, frame_type, ct, dts, pts, sample, nb_sample)) != srs_success) {
|
||||
if ((err = enc->write_sample(format, SrsMp4HandlerTypeVIDE, frame_type, ct, dts, pts, sample, nb_sample)) != srs_success) {
|
||||
return srs_error_wrap(err, "write sample");
|
||||
}
|
||||
|
||||
|
|
|
@ -157,10 +157,10 @@ srs_error_t SrsVodStream::serve_mp4_stream(ISrsHttpResponseWriter* w, ISrsHttpMe
|
|||
|
||||
// parse -1 to whole file.
|
||||
if (end == -1) {
|
||||
end = (int)fs->filesize();
|
||||
end = (int)(fs->filesize() - 1);
|
||||
}
|
||||
|
||||
if (end > fs->filesize() || start > end) {
|
||||
if (end > fs->filesize() || start > end || end < 0) {
|
||||
return srs_error_new(ERROR_HTTP_REMUX_OFFSET_OVERFLOW, "http mp4 streaming %s overflow. size=%" PRId64 ", offset=%d",
|
||||
fullpath.c_str(), fs->filesize(), start);
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
// The version config.
|
||||
#define VERSION_MAJOR 3
|
||||
#define VERSION_MINOR 0
|
||||
#define VERSION_REVISION 85
|
||||
#define VERSION_REVISION 88
|
||||
|
||||
// The macros generated by configure script.
|
||||
#include <srs_auto_headers.hpp>
|
||||
|
|
|
@ -62,6 +62,7 @@ SrsCplxError::SrsCplxError()
|
|||
|
||||
SrsCplxError::~SrsCplxError()
|
||||
{
|
||||
srs_freep(wrapped);
|
||||
}
|
||||
|
||||
std::string SrsCplxError::description() {
|
||||
|
|
|
@ -408,6 +408,7 @@ srs_error_t SrsMp4Box::discovery(SrsBuffer* buf, SrsMp4Box** ppbox)
|
|||
case SrsMp4BoxTypeTFHD: box = new SrsMp4TrackFragmentHeaderBox(); break;
|
||||
case SrsMp4BoxTypeTFDT: box = new SrsMp4TrackFragmentDecodeTimeBox(); break;
|
||||
case SrsMp4BoxTypeTRUN: box = new SrsMp4TrackFragmentRunBox(); break;
|
||||
case SrsMp4BoxTypeSIDX: box = new SrsMp4SegmentIndexBox(); break;
|
||||
// Skip some unknown boxes.
|
||||
case SrsMp4BoxTypeFREE: case SrsMp4BoxTypeSKIP: case SrsMp4BoxTypePASP:
|
||||
box = new SrsMp4FreeSpaceBox(type); break;
|
||||
|
@ -2047,10 +2048,8 @@ stringstream& SrsMp4TrackHeaderBox::dumps_detail(stringstream& ss, SrsMp4DumpCon
|
|||
if (volume) {
|
||||
ss << ", volume=" << uint32_t(volume>>8) << "." << uint32_t(volume&0xFF);
|
||||
}
|
||||
|
||||
if (width || height) {
|
||||
ss << ", size=" << uint16_t(width>>16) << "x" << uint16_t(height>>16);
|
||||
}
|
||||
|
||||
ss << ", size=" << uint16_t(width>>16) << "x" << uint16_t(height>>16);
|
||||
|
||||
return ss;
|
||||
}
|
||||
|
@ -4577,6 +4576,120 @@ stringstream& SrsMp4UserDataBox::dumps_detail(stringstream& ss, SrsMp4DumpContex
|
|||
return ss;
|
||||
}
|
||||
|
||||
SrsMp4SegmentIndexBox::SrsMp4SegmentIndexBox()
|
||||
{
|
||||
type = SrsMp4BoxTypeSIDX;
|
||||
}
|
||||
|
||||
SrsMp4SegmentIndexBox::~SrsMp4SegmentIndexBox()
|
||||
{
|
||||
}
|
||||
|
||||
int SrsMp4SegmentIndexBox::nb_header()
|
||||
{
|
||||
return SrsMp4Box::nb_header() + 4+4+4 + (version? 4:8) + 4+4 + 12*entries.size();
|
||||
}
|
||||
|
||||
srs_error_t SrsMp4SegmentIndexBox::encode_header(SrsBuffer* buf)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if ((err = SrsMp4Box::encode_header(buf)) != srs_success) {
|
||||
return srs_error_wrap(err, "encode header");
|
||||
}
|
||||
|
||||
buf->write_1bytes(version);
|
||||
buf->write_3bytes(flags);
|
||||
buf->write_4bytes(reference_id);
|
||||
buf->write_4bytes(timescale);
|
||||
if (!version) {
|
||||
buf->write_4bytes(earliest_presentation_time);
|
||||
buf->write_4bytes(first_offset);
|
||||
} else {
|
||||
buf->write_8bytes(earliest_presentation_time);
|
||||
buf->write_8bytes(first_offset);
|
||||
}
|
||||
|
||||
buf->write_4bytes((uint32_t)entries.size());
|
||||
for (int i = 0; i < (int)entries.size(); i++) {
|
||||
SrsMp4SegmentIndexEntry& entry = entries.at(i);
|
||||
|
||||
uint32_t v = uint32_t(entry.reference_type&0x01)<<31;
|
||||
v |= entry.referenced_size&0x7fffffff;
|
||||
buf->write_4bytes(v);
|
||||
|
||||
buf->write_4bytes(entry.subsegment_duration);
|
||||
|
||||
v = uint32_t(entry.starts_with_SAP&0x01)<<31;
|
||||
v |= uint32_t(entry.SAP_type&0x7)<<28;
|
||||
v |= entry.SAP_delta_time&0xfffffff;
|
||||
buf->write_4bytes(v);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsMp4SegmentIndexBox::decode_header(SrsBuffer* buf)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if ((err = SrsMp4Box::decode_header(buf)) != srs_success) {
|
||||
return srs_error_wrap(err, "decode header");
|
||||
}
|
||||
|
||||
version = buf->read_1bytes();
|
||||
flags = buf->read_3bytes();
|
||||
reference_id = buf->read_4bytes();
|
||||
timescale = buf->read_4bytes();
|
||||
if (!version) {
|
||||
earliest_presentation_time = buf->read_4bytes();
|
||||
first_offset = buf->read_4bytes();
|
||||
} else {
|
||||
earliest_presentation_time = buf->read_8bytes();
|
||||
first_offset = buf->read_8bytes();
|
||||
}
|
||||
|
||||
uint32_t nn_entries = (uint32_t)(buf->read_4bytes() & 0xffff);
|
||||
for (uint32_t i = 0; i < nn_entries; i++) {
|
||||
SrsMp4SegmentIndexEntry entry;
|
||||
|
||||
uint32_t v = buf->read_4bytes();
|
||||
entry.reference_type = uint8_t((v&0x80000000)>>31);
|
||||
entry.referenced_size = v&0x7fffffff;
|
||||
|
||||
entry.subsegment_duration = buf->read_4bytes();
|
||||
|
||||
v = buf->read_4bytes();
|
||||
entry.starts_with_SAP = uint8_t((v&0x80000000)>>31);
|
||||
entry.SAP_type = uint8_t((v&0x70000000)>>28);
|
||||
entry.SAP_delta_time = v&0xfffffff;
|
||||
|
||||
entries.push_back(entry);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
stringstream& SrsMp4SegmentIndexBox::dumps_detail(stringstream& ss, SrsMp4DumpContext dc)
|
||||
{
|
||||
SrsMp4Box::dumps_detail(ss, dc);
|
||||
|
||||
ss << ", v" << (int)version << ", flags=" << flags << ", refs#" << reference_id
|
||||
<< ", TBN=" << timescale << ", ePTS=" << earliest_presentation_time;
|
||||
|
||||
for (int i = 0; i < (int)entries.size(); i++) {
|
||||
SrsMp4SegmentIndexEntry& entry = entries.at(i);
|
||||
|
||||
ss << endl;
|
||||
srs_padding(ss, dc.indent());
|
||||
ss << "#" << i << ", ref=" << (int)entry.reference_type << "/" << entry.referenced_size
|
||||
<< ", duration=" << entry.subsegment_duration << ", SAP=" << (int)entry.starts_with_SAP
|
||||
<< "/" << (int)entry.SAP_type << "/" << entry.SAP_delta_time;
|
||||
}
|
||||
|
||||
return ss;
|
||||
}
|
||||
|
||||
SrsMp4Sample::SrsMp4Sample()
|
||||
{
|
||||
type = SrsFrameTypeForbidden;
|
||||
|
@ -5528,6 +5641,26 @@ srs_error_t SrsMp4Encoder::initialize(ISrsWriteSeeker* ws)
|
|||
return srs_error_wrap(err, "write ftyp");
|
||||
}
|
||||
}
|
||||
|
||||
// 8B reserved free box.
|
||||
if (true) {
|
||||
SrsMp4FreeSpaceBox* freeb = new SrsMp4FreeSpaceBox(SrsMp4BoxTypeFREE);
|
||||
SrsAutoFree(SrsMp4FreeSpaceBox, freeb);
|
||||
|
||||
int nb_data = freeb->nb_bytes();
|
||||
std::vector<char> data(nb_data);
|
||||
|
||||
SrsBuffer* buffer = new SrsBuffer(&data[0], nb_data);
|
||||
SrsAutoFree(SrsBuffer, buffer);
|
||||
|
||||
if ((err = freeb->encode(buffer)) != srs_success) {
|
||||
return srs_error_wrap(err, "encode free box");
|
||||
}
|
||||
|
||||
if ((err = wsio->write(&data[0], nb_data, NULL)) != srs_success) {
|
||||
return srs_error_wrap(err, "write free box");
|
||||
}
|
||||
}
|
||||
|
||||
// Write mdat box.
|
||||
if (true) {
|
||||
|
@ -5564,8 +5697,10 @@ srs_error_t SrsMp4Encoder::initialize(ISrsWriteSeeker* ws)
|
|||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsMp4Encoder::write_sample(SrsMp4HandlerType ht, uint16_t ft, uint16_t ct, uint32_t dts, uint32_t pts, uint8_t* sample, uint32_t nb_sample)
|
||||
{
|
||||
srs_error_t SrsMp4Encoder::write_sample(
|
||||
SrsFormat* format, SrsMp4HandlerType ht, uint16_t ft, uint16_t ct, uint32_t dts, uint32_t pts,
|
||||
uint8_t* sample, uint32_t nb_sample
|
||||
) {
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
SrsMp4Sample* ps = new SrsMp4Sample();
|
||||
|
@ -5574,7 +5709,7 @@ srs_error_t SrsMp4Encoder::write_sample(SrsMp4HandlerType ht, uint16_t ft, uint1
|
|||
bool vsh = (ht == SrsMp4HandlerTypeVIDE) && (ct == (uint16_t)SrsVideoAvcFrameTraitSequenceHeader);
|
||||
bool ash = (ht == SrsMp4HandlerTypeSOUN) && (ct == (uint16_t)SrsAudioAacFrameTraitSequenceHeader);
|
||||
if (vsh || ash) {
|
||||
err = copy_sequence_header(vsh, sample, nb_sample);
|
||||
err = copy_sequence_header(format, vsh, sample, nb_sample);
|
||||
srs_freep(ps);
|
||||
return err;
|
||||
}
|
||||
|
@ -5683,6 +5818,7 @@ srs_error_t SrsMp4Encoder::flush()
|
|||
|
||||
avc1->width = width;
|
||||
avc1->height = height;
|
||||
avc1->data_reference_index = 1;
|
||||
|
||||
SrsMp4AvccBox* avcC = new SrsMp4AvccBox();
|
||||
avc1->set_avcC(avcC);
|
||||
|
@ -5741,6 +5877,7 @@ srs_error_t SrsMp4Encoder::flush()
|
|||
stbl->set_stsd(stsd);
|
||||
|
||||
SrsMp4AudioSampleEntry* mp4a = new SrsMp4AudioSampleEntry();
|
||||
mp4a->data_reference_index = 1;
|
||||
mp4a->samplerate = uint32_t(srs_flv_srates[sample_rate]) << 16;
|
||||
if (sound_bits == SrsAudioSampleBits16bit) {
|
||||
mp4a->samplesize = 16;
|
||||
|
@ -5826,7 +5963,7 @@ srs_error_t SrsMp4Encoder::flush()
|
|||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsMp4Encoder::copy_sequence_header(bool vsh, uint8_t* sample, uint32_t nb_sample)
|
||||
srs_error_t SrsMp4Encoder::copy_sequence_header(SrsFormat* format, bool vsh, uint8_t* sample, uint32_t nb_sample)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
|
@ -5848,8 +5985,10 @@ srs_error_t SrsMp4Encoder::copy_sequence_header(bool vsh, uint8_t* sample, uint3
|
|||
|
||||
if (vsh) {
|
||||
pavcc = std::vector<char>(sample, sample + nb_sample);
|
||||
|
||||
// TODO: FIXME: Parse the width and height.
|
||||
if (format && format->vcodec) {
|
||||
width = format->vcodec->width;
|
||||
height = format->vcodec->height;
|
||||
}
|
||||
}
|
||||
|
||||
if (!vsh) {
|
||||
|
@ -5906,8 +6045,8 @@ srs_error_t SrsMp4M2tsInitEncoder::write(SrsFormat* format, bool video, int tid)
|
|||
SrsAutoFree(SrsMp4FileTypeBox, ftyp);
|
||||
if (true) {
|
||||
ftyp->major_brand = SrsMp4BoxBrandISO5;
|
||||
ftyp->minor_version = 0;
|
||||
ftyp->set_compatible_brands(SrsMp4BoxBrandISOM, SrsMp4BoxBrandISO5, SrsMp4BoxBrandDASH, SrsMp4BoxBrandMP42);
|
||||
ftyp->minor_version = 512;
|
||||
ftyp->set_compatible_brands(SrsMp4BoxBrandISO6, SrsMp4BoxBrandMP41);
|
||||
}
|
||||
|
||||
// Write moov.
|
||||
|
@ -5977,6 +6116,7 @@ srs_error_t SrsMp4M2tsInitEncoder::write(SrsFormat* format, bool video, int tid)
|
|||
|
||||
avc1->width = format->vcodec->width;
|
||||
avc1->height = format->vcodec->height;
|
||||
avc1->data_reference_index = 1;
|
||||
|
||||
SrsMp4AvccBox* avcC = new SrsMp4AvccBox();
|
||||
avc1->set_avcC(avcC);
|
||||
|
@ -6054,6 +6194,7 @@ srs_error_t SrsMp4M2tsInitEncoder::write(SrsFormat* format, bool video, int tid)
|
|||
stbl->set_stsd(stsd);
|
||||
|
||||
SrsMp4AudioSampleEntry* mp4a = new SrsMp4AudioSampleEntry();
|
||||
mp4a->data_reference_index = 1;
|
||||
mp4a->samplerate = uint32_t(srs_flv_srates[format->acodec->sound_rate]) << 16;
|
||||
if (format->acodec->sound_size == SrsAudioSampleBits16bit) {
|
||||
mp4a->samplesize = 16;
|
||||
|
@ -6109,7 +6250,7 @@ srs_error_t SrsMp4M2tsInitEncoder::write(SrsFormat* format, bool video, int tid)
|
|||
uint8_t* data = new uint8_t[nb_data];
|
||||
SrsAutoFreeA(uint8_t, data);
|
||||
|
||||
SrsBuffer* buffer = new SrsBuffer();
|
||||
SrsBuffer* buffer = new SrsBuffer((char*)data, nb_data);
|
||||
SrsAutoFree(SrsBuffer, buffer);
|
||||
|
||||
if ((err = ftyp->encode(buffer)) != srs_success) {
|
||||
|
@ -6134,7 +6275,6 @@ SrsMp4M2tsSegmentEncoder::SrsMp4M2tsSegmentEncoder()
|
|||
buffer = new SrsBuffer();
|
||||
sequence_number = 0;
|
||||
decode_basetime = 0;
|
||||
data_offset = 0;
|
||||
mdat_bytes = 0;
|
||||
}
|
||||
|
||||
|
@ -6160,7 +6300,7 @@ srs_error_t SrsMp4M2tsSegmentEncoder::initialize(ISrsWriter* w, uint32_t sequenc
|
|||
|
||||
styp->major_brand = SrsMp4BoxBrandMSDH;
|
||||
styp->minor_version = 0;
|
||||
styp->set_compatible_brands(SrsMp4BoxBrandMSDH, SrsMp4BoxBrandDASH);
|
||||
styp->set_compatible_brands(SrsMp4BoxBrandMSDH, SrsMp4BoxBrandMSIX);
|
||||
|
||||
int nb_data = styp->nb_bytes();
|
||||
std::vector<char> data(nb_data);
|
||||
|
@ -6176,9 +6316,8 @@ srs_error_t SrsMp4M2tsSegmentEncoder::initialize(ISrsWriter* w, uint32_t sequenc
|
|||
if ((err = writer->write(&data[0], nb_data, NULL)) != srs_success) {
|
||||
return srs_error_wrap(err, "write styp");
|
||||
}
|
||||
|
||||
data_offset = nb_data;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -6204,7 +6343,11 @@ srs_error_t SrsMp4M2tsSegmentEncoder::write_sample(SrsMp4HandlerType ht,
|
|||
ps->tbn = 1000;
|
||||
ps->dts = dts;
|
||||
ps->pts = pts;
|
||||
ps->data = sample;
|
||||
|
||||
// We should copy the sample data, which is shared ptr from video/audio message.
|
||||
// Furthermore, we do free the data when freeing the sample.
|
||||
ps->data = new uint8_t[nb_sample];
|
||||
memcpy(ps->data, sample, nb_sample);
|
||||
ps->nb_data = nb_sample;
|
||||
|
||||
// Append to manager to build the moof.
|
||||
|
@ -6228,7 +6371,10 @@ srs_error_t SrsMp4M2tsSegmentEncoder::flush(uint64_t& dts)
|
|||
// and we will update its header(size) when flush.
|
||||
SrsMp4MediaDataBox* mdat = new SrsMp4MediaDataBox();
|
||||
SrsAutoFree(SrsMp4MediaDataBox, mdat);
|
||||
|
||||
|
||||
// Although the sidx is not required to start play DASH, but it's required for AV sync.
|
||||
// TODO: FIXME: Insert a sidx box.
|
||||
|
||||
// Write moof.
|
||||
if (true) {
|
||||
SrsMp4MovieFragmentBox* moof = new SrsMp4MovieFragmentBox();
|
||||
|
@ -6262,7 +6408,8 @@ srs_error_t SrsMp4M2tsSegmentEncoder::flush(uint64_t& dts)
|
|||
}
|
||||
|
||||
int nb_data = moof->nb_bytes();
|
||||
trun->data_offset = (int32_t)(data_offset + nb_data + mdat->sz_header());
|
||||
// @remark Remember the data_offset of turn is size(moof)+header(mdat), not including styp or sidx.
|
||||
trun->data_offset = (int32_t)(nb_data + mdat->sz_header());
|
||||
|
||||
uint8_t* data = new uint8_t[nb_data];
|
||||
SrsAutoFreeA(uint8_t, data);
|
||||
|
|
|
@ -123,6 +123,7 @@ enum SrsMp4BoxType
|
|||
SrsMp4BoxTypeTFHD = 0x74666864, // 'tfhd'
|
||||
SrsMp4BoxTypeTFDT = 0x74666474, // 'tfdt'
|
||||
SrsMp4BoxTypeTRUN = 0x7472756e, // 'trun'
|
||||
SrsMp4BoxTypeSIDX = 0x73696478, // 'sidx'
|
||||
};
|
||||
|
||||
// 8.4.3.3 Semantics
|
||||
|
@ -145,9 +146,11 @@ enum SrsMp4BoxBrand
|
|||
SrsMp4BoxBrandAVC1 = 0x61766331, // 'avc1'
|
||||
SrsMp4BoxBrandMP41 = 0x6d703431, // 'mp41'
|
||||
SrsMp4BoxBrandISO5 = 0x69736f35, // 'iso5'
|
||||
SrsMp4BoxBrandISO6 = 0x69736f36, // 'iso6'
|
||||
SrsMp4BoxBrandMP42 = 0x6d703432, // 'mp42'
|
||||
SrsMp4BoxBrandDASH = 0x64617368, // 'dash'
|
||||
SrsMp4BoxBrandMSDH = 0x6d736468, // 'msdh'
|
||||
SrsMp4BoxBrandMSIX = 0x6d736978, // 'msix'
|
||||
};
|
||||
|
||||
// The context to dump.
|
||||
|
@ -179,8 +182,10 @@ public:
|
|||
// An extended type; in this case, the type field is set to ‘uuid’.
|
||||
SrsMp4BoxType type;
|
||||
// For box 'uuid'.
|
||||
// TODO: FIXME: Should double check buffer.
|
||||
std::vector<char> usertype;
|
||||
protected:
|
||||
// TODO: FIXME: Should double check buffer.
|
||||
std::vector<SrsMp4Box*> boxes;
|
||||
private:
|
||||
// The position at buffer to start demux the box.
|
||||
|
@ -274,6 +279,7 @@ public:
|
|||
uint32_t minor_version;
|
||||
private:
|
||||
// A list, to the end of the box, of brands
|
||||
// TODO: FIXME: Should double check buffer.
|
||||
std::vector<SrsMp4BoxBrand> compatible_brands;
|
||||
public:
|
||||
SrsMp4FileTypeBox();
|
||||
|
@ -506,6 +512,7 @@ public:
|
|||
uint32_t first_sample_flags;
|
||||
// all fields in the following array are optional
|
||||
public:
|
||||
// TODO: FIXME: Should double check buffer.
|
||||
std::vector<SrsMp4TrunEntry*> entries;
|
||||
public:
|
||||
SrsMp4TrackFragmentRunBox();
|
||||
|
@ -595,6 +602,7 @@ public:
|
|||
class SrsMp4FreeSpaceBox : public SrsMp4Box
|
||||
{
|
||||
private:
|
||||
// TODO: FIXME: Should double check buffer.
|
||||
std::vector<char> data;
|
||||
public:
|
||||
SrsMp4FreeSpaceBox(SrsMp4BoxType v);
|
||||
|
@ -902,6 +910,7 @@ class SrsMp4EditListBox : public SrsMp4FullBox
|
|||
{
|
||||
public:
|
||||
// An integer that gives the number of entries in the following table
|
||||
// TODO: FIXME: Should double check buffer.
|
||||
std::vector<SrsMp4ElstEntry> entries;
|
||||
public:
|
||||
SrsMp4EditListBox();
|
||||
|
@ -1152,6 +1161,7 @@ public:
|
|||
class SrsMp4DataReferenceBox : public SrsMp4FullBox
|
||||
{
|
||||
private:
|
||||
// TODO: FIXME: Should double check buffer.
|
||||
std::vector<SrsMp4DataEntryBox*> entries;
|
||||
public:
|
||||
SrsMp4DataReferenceBox();
|
||||
|
@ -1273,6 +1283,7 @@ public:
|
|||
class SrsMp4AvccBox : public SrsMp4Box
|
||||
{
|
||||
public:
|
||||
// TODO: FIXME: Should double check buffer.
|
||||
std::vector<char> avc_config;
|
||||
public:
|
||||
SrsMp4AvccBox();
|
||||
|
@ -1383,6 +1394,7 @@ class SrsMp4DecoderSpecificInfo : public SrsMp4BaseDescriptor
|
|||
public:
|
||||
// AAC Audio Specific Config.
|
||||
// 1.6.2.1 AudioSpecificConfig, in ISO_IEC_14496-3-AAC-2001.pdf, page 33.
|
||||
// TODO: FIXME: Should double check buffer.
|
||||
std::vector<char> asc;
|
||||
public:
|
||||
SrsMp4DecoderSpecificInfo();
|
||||
|
@ -1449,6 +1461,7 @@ public:
|
|||
// if (streamDependenceFlag)
|
||||
uint16_t dependsOn_ES_ID;
|
||||
// if (URL_Flag)
|
||||
// TODO: FIXME: Should double check buffer.
|
||||
std::vector<char> URLstring;
|
||||
// if (OCRstreamFlag)
|
||||
uint16_t OCR_ES_Id;
|
||||
|
@ -1494,6 +1507,7 @@ public:
|
|||
class SrsMp4SampleDescriptionBox : public SrsMp4FullBox
|
||||
{
|
||||
private:
|
||||
// TODO: FIXME: Should double check buffer.
|
||||
std::vector<SrsMp4SampleEntry*> entries;
|
||||
public:
|
||||
SrsMp4SampleDescriptionBox();
|
||||
|
@ -1543,6 +1557,7 @@ class SrsMp4DecodingTime2SampleBox : public SrsMp4FullBox
|
|||
{
|
||||
public:
|
||||
// An integer that gives the number of entries in the following table.
|
||||
// TODO: FIXME: Should double check buffer.
|
||||
std::vector<SrsMp4SttsEntry> entries;
|
||||
private:
|
||||
// The index for counter to calc the dts for samples.
|
||||
|
@ -1783,6 +1798,7 @@ public:
|
|||
class SrsMp4UserDataBox : public SrsMp4Box
|
||||
{
|
||||
public:
|
||||
// TODO: FIXME: Should double check buffer.
|
||||
std::vector<char> data;
|
||||
public:
|
||||
SrsMp4UserDataBox();
|
||||
|
@ -1795,6 +1811,44 @@ public:
|
|||
virtual std::stringstream& dumps_detail(std::stringstream& ss, SrsMp4DumpContext dc);
|
||||
};
|
||||
|
||||
// The entry for SegmentIndexBox(sidx) for MPEG-DASH.
|
||||
// @doc https://patches.videolan.org/patch/103/
|
||||
struct SrsMp4SegmentIndexEntry
|
||||
{
|
||||
uint8_t reference_type; // 1bit
|
||||
uint32_t referenced_size; // 31bits
|
||||
uint32_t subsegment_duration; // 32bits
|
||||
uint8_t starts_with_SAP; // 1bit
|
||||
uint8_t SAP_type; // 3bits
|
||||
uint32_t SAP_delta_time; // 28bits
|
||||
};
|
||||
|
||||
// The SegmentIndexBox(sidx) for MPEG-DASH.
|
||||
// @doc https://gpac.wp.imt.fr/2012/02/01/dash-support/
|
||||
// @doc https://patches.videolan.org/patch/103/
|
||||
// @doc https://github.com/necccc/iso-bmff-parser-stream/blob/master/lib/box/sidx.js
|
||||
class SrsMp4SegmentIndexBox : public SrsMp4Box
|
||||
{
|
||||
public:
|
||||
uint8_t version;
|
||||
uint32_t flags;
|
||||
uint32_t reference_id;
|
||||
uint32_t timescale;
|
||||
uint64_t earliest_presentation_time;
|
||||
uint32_t first_offset;
|
||||
// TODO: FIXME: Should double check buffer.
|
||||
std::vector<SrsMp4SegmentIndexEntry> entries;
|
||||
public:
|
||||
SrsMp4SegmentIndexBox();
|
||||
virtual ~SrsMp4SegmentIndexBox();
|
||||
protected:
|
||||
virtual int nb_header();
|
||||
virtual srs_error_t encode_header(SrsBuffer* buf);
|
||||
virtual srs_error_t decode_header(SrsBuffer* buf);
|
||||
public:
|
||||
virtual std::stringstream& dumps_detail(std::stringstream& ss, SrsMp4DumpContext dc);
|
||||
};
|
||||
|
||||
// Generally, a MP4 sample contains a frame, for example, a video frame or audio frame.
|
||||
class SrsMp4Sample
|
||||
{
|
||||
|
@ -2024,12 +2078,12 @@ public:
|
|||
// @param pts The output pts in milliseconds.
|
||||
// @param sample The output payload, user must free it.
|
||||
// @param nb_sample The output size of payload.
|
||||
virtual srs_error_t write_sample(SrsMp4HandlerType ht, uint16_t ft, uint16_t ct,
|
||||
virtual srs_error_t write_sample(SrsFormat* format, SrsMp4HandlerType ht, uint16_t ft, uint16_t ct,
|
||||
uint32_t dts, uint32_t pts, uint8_t* sample, uint32_t nb_sample);
|
||||
// Flush the encoder, to write the moov.
|
||||
virtual srs_error_t flush();
|
||||
private:
|
||||
virtual srs_error_t copy_sequence_header(bool vsh, uint8_t* sample, uint32_t nb_sample);
|
||||
virtual srs_error_t copy_sequence_header(SrsFormat* format, bool vsh, uint8_t* sample, uint32_t nb_sample);
|
||||
virtual srs_error_t do_write_sample(SrsMp4Sample* ps, uint8_t* sample, uint32_t nb_sample);
|
||||
};
|
||||
|
||||
|
@ -2063,8 +2117,6 @@ private:
|
|||
uint32_t nb_videos;
|
||||
uint64_t mdat_bytes;
|
||||
SrsMp4SampleManager* samples;
|
||||
private:
|
||||
uint64_t data_offset;
|
||||
public:
|
||||
SrsMp4M2tsSegmentEncoder();
|
||||
virtual ~SrsMp4M2tsSegmentEncoder();
|
||||
|
|
|
@ -40,28 +40,19 @@ using namespace std;
|
|||
ISrsLog* _srs_log = new SrsConsoleLog(SrsLogLevelTrace, false);
|
||||
ISrsThreadContext* _srs_context = new SrsThreadContext();
|
||||
|
||||
int parse(std::string mp4_file, bool verbose)
|
||||
srs_error_t parse(std::string mp4_file, bool verbose)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
SrsFileReader fr;
|
||||
if ((err = fr.open(mp4_file)) != srs_success) {
|
||||
// TODO: FIXME: Use error
|
||||
ret = srs_error_code(err);
|
||||
srs_freep(err);
|
||||
srs_error("Open MP4 file failed, ret=%d", ret);
|
||||
return ret;
|
||||
return srs_error_wrap(err, "open mp4 file %s", mp4_file.c_str());
|
||||
}
|
||||
srs_trace("MP4 file open success");
|
||||
|
||||
SrsMp4BoxReader br;
|
||||
if ((err = br.initialize(&fr)) != srs_success) {
|
||||
// TODO: FIXME: Use error
|
||||
ret = srs_error_code(err);
|
||||
srs_freep(err);
|
||||
srs_error("Open MP4 box reader failed, ret=%d", ret);
|
||||
return ret;
|
||||
return srs_error_wrap(err, "open box reader");
|
||||
}
|
||||
srs_trace("MP4 box reader open success");
|
||||
|
||||
|
@ -74,34 +65,21 @@ int parse(std::string mp4_file, bool verbose)
|
|||
SrsAutoFree(SrsMp4Box, box);
|
||||
|
||||
if ((err = br.read(stream, &box)) != srs_success) {
|
||||
// TODO: FIXME: Use error
|
||||
ret = srs_error_code(err);
|
||||
srs_freep(err);
|
||||
if (ret != ERROR_SYSTEM_FILE_EOF) {
|
||||
srs_error("Read MP4 box failed, ret=%d", ret);
|
||||
} else {
|
||||
if (srs_error_code(err) == ERROR_SYSTEM_FILE_EOF) {
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
return ret;
|
||||
return srs_error_wrap(err, "read box");
|
||||
}
|
||||
|
||||
SrsBuffer* buffer = new SrsBuffer(stream->bytes(), stream->length());
|
||||
SrsAutoFree(SrsBuffer, buffer);
|
||||
|
||||
if ((err = box->decode(buffer)) != srs_success) {
|
||||
// TODO: FIXME: Use error
|
||||
ret = srs_error_code(err);
|
||||
srs_freep(err);
|
||||
srs_error("Decode the box failed, ret=%d", ret);
|
||||
return ret;
|
||||
return srs_error_wrap(err, "decode box");
|
||||
}
|
||||
|
||||
if ((err = br.skip(box, stream)) != srs_success) {
|
||||
// TODO: FIXME: Use error
|
||||
ret = srs_error_code(err);
|
||||
srs_freep(err);
|
||||
srs_error("Skip MP4 box failed, ret=%d", ret);
|
||||
return ret;
|
||||
return srs_error_wrap(err, "skip box");
|
||||
}
|
||||
|
||||
SrsMp4DumpContext ctx;
|
||||
|
@ -112,13 +90,11 @@ int parse(std::string mp4_file, bool verbose)
|
|||
fprintf(stderr, "%s", box->dumps(ss, ctx).str().c_str());
|
||||
}
|
||||
|
||||
return ret;
|
||||
return err;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
printf("SRS MP4 parser/%d.%d.%d, parse and show the mp4 boxes structure.\n",
|
||||
VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION);
|
||||
|
||||
|
@ -140,13 +116,16 @@ int main(int argc, char** argv)
|
|||
}
|
||||
srs_trace("Parse MP4 file %s, verbose=%d", mp4_file.c_str(), verbose);
|
||||
|
||||
ret = parse(mp4_file, verbose);
|
||||
|
||||
if (ret == ERROR_SYSTEM_FILE_EOF) {
|
||||
srs_error_t err = parse(mp4_file, verbose);
|
||||
int code = srs_error_code(err);
|
||||
|
||||
if (code == ERROR_SYSTEM_FILE_EOF) {
|
||||
srs_trace("Parse complete");
|
||||
return 0;
|
||||
} else {
|
||||
srs_error("Parse error %s", srs_error_desc(err).c_str());
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
srs_freep(err);
|
||||
return code;
|
||||
}
|
||||
|
||||
|
|
|
@ -486,6 +486,15 @@ srs_error_t SrsHttpFileServer::serve_mp4_file(ISrsHttpResponseWriter* w, ISrsHtt
|
|||
if (range.empty()) {
|
||||
range = r->query_get("bytes");
|
||||
}
|
||||
|
||||
// Fetch range from header.
|
||||
SrsHttpHeader* h = r->header();
|
||||
if (range.empty() && h) {
|
||||
range = h->get("Range");
|
||||
if (range.find("bytes=") == 0) {
|
||||
range = range.substr(6);
|
||||
}
|
||||
}
|
||||
|
||||
// rollback to serve whole file.
|
||||
size_t pos = string::npos;
|
||||
|
|
|
@ -4589,7 +4589,7 @@ VOID TEST(KernelMP4Test, CoverMP4Codec)
|
|||
};
|
||||
EXPECT_TRUE(srs_success == fmt.on_video(0, (char*)raw, sizeof(raw)));
|
||||
EXPECT_TRUE(srs_success == enc.write_sample(
|
||||
SrsMp4HandlerTypeVIDE, fmt.video->frame_type, fmt.video->avc_packet_type, 0, 0, (uint8_t*)fmt.raw, fmt.nb_raw
|
||||
NULL, SrsMp4HandlerTypeVIDE, fmt.video->frame_type, fmt.video->avc_packet_type, 0, 0, (uint8_t*)fmt.raw, fmt.nb_raw
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -4599,7 +4599,7 @@ VOID TEST(KernelMP4Test, CoverMP4Codec)
|
|||
};
|
||||
EXPECT_TRUE(srs_success == fmt.on_audio(0, (char*)raw, sizeof(raw)));
|
||||
EXPECT_TRUE(srs_success == enc.write_sample(
|
||||
SrsMp4HandlerTypeSOUN, 0x00, fmt.audio->aac_packet_type, 0, 0, (uint8_t*)fmt.raw, fmt.nb_raw
|
||||
NULL, SrsMp4HandlerTypeSOUN, 0x00, fmt.audio->aac_packet_type, 0, 0, (uint8_t*)fmt.raw, fmt.nb_raw
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -4615,7 +4615,7 @@ VOID TEST(KernelMP4Test, CoverMP4Codec)
|
|||
};
|
||||
EXPECT_TRUE(srs_success == fmt.on_audio(0, (char*)raw, sizeof(raw)));
|
||||
EXPECT_TRUE(srs_success == enc.write_sample(
|
||||
SrsMp4HandlerTypeSOUN, 0x00, fmt.audio->aac_packet_type, 34, 34, (uint8_t*)fmt.raw, fmt.nb_raw
|
||||
NULL, SrsMp4HandlerTypeSOUN, 0x00, fmt.audio->aac_packet_type, 34, 34, (uint8_t*)fmt.raw, fmt.nb_raw
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -4634,7 +4634,7 @@ VOID TEST(KernelMP4Test, CoverMP4Codec)
|
|||
};
|
||||
EXPECT_TRUE(srs_success == fmt.on_video(0, (char*)raw, sizeof(raw)));
|
||||
EXPECT_TRUE(srs_success == enc.write_sample(
|
||||
SrsMp4HandlerTypeVIDE, fmt.video->frame_type, fmt.video->avc_packet_type, 40, 40, (uint8_t*)fmt.raw, fmt.nb_raw
|
||||
NULL, SrsMp4HandlerTypeVIDE, fmt.video->frame_type, fmt.video->avc_packet_type, 40, 40, (uint8_t*)fmt.raw, fmt.nb_raw
|
||||
));
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue