mirror of
https://github.com/ossrs/srs.git
synced 2025-02-14 20:31:56 +00:00
For #299, A/V init mp4 are fine.
This commit is contained in:
parent
886930c22a
commit
3ec9df6578
6 changed files with 461 additions and 8 deletions
|
@ -31,6 +31,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
#include <srs_kernel_utility.hpp>
|
||||
#include <srs_app_utility.hpp>
|
||||
#include <srs_kernel_file.hpp>
|
||||
#include <srs_core_autofree.hpp>
|
||||
#include <srs_kernel_mp4.hpp>
|
||||
|
||||
#include <sstream>
|
||||
using namespace std;
|
||||
|
@ -119,15 +121,17 @@ int SrsMpdWriter::write(SrsFormat* format)
|
|||
ss << " </Period>" << endl
|
||||
<< "</MPD>" << endl;
|
||||
|
||||
SrsFileWriter fw;
|
||||
SrsFileWriter* fw = new SrsFileWriter();
|
||||
SrsAutoFree(SrsFileWriter, fw);
|
||||
|
||||
string full_path_tmp = full_path + ".tmp";
|
||||
if ((ret = fw.open(full_path_tmp)) != ERROR_SUCCESS) {
|
||||
if ((ret = fw->open(full_path_tmp)) != ERROR_SUCCESS) {
|
||||
srs_error("DASH: Open MPD file=%s failed, ret=%d", full_path_tmp.c_str(), ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
string content = ss.str();
|
||||
if ((ret = fw.write((void*)content.data(), content.length(), NULL)) != ERROR_SUCCESS) {
|
||||
if ((ret = fw->write((void*)content.data(), content.length(), NULL)) != ERROR_SUCCESS) {
|
||||
srs_error("DASH: Write MPD file=%s failed, ret=%d", full_path.c_str(), ret);
|
||||
return ret;
|
||||
}
|
||||
|
@ -138,13 +142,16 @@ int SrsMpdWriter::write(SrsFormat* format)
|
|||
return ret;
|
||||
}
|
||||
|
||||
srs_trace("DASH: Refresh MPD successed, size=%dB, file=%s", content.length(), full_path.c_str());
|
||||
srs_trace("DASH: Refresh MPD success, size=%dB, file=%s", content.length(), full_path.c_str());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
SrsDashController::SrsDashController()
|
||||
{
|
||||
req = NULL;
|
||||
video_tack_id = 2;
|
||||
audio_track_id = 1;
|
||||
mpd = new SrsMpdWriter();
|
||||
}
|
||||
|
||||
|
@ -157,6 +164,9 @@ int SrsDashController::initialize(SrsRequest* r)
|
|||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
req = r;
|
||||
home = _srs_config->get_dash_path(r->vhost);
|
||||
|
||||
if ((ret = mpd->initialize(r)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
@ -168,6 +178,10 @@ int SrsDashController::on_audio(SrsSharedPtrMessage* shared_audio, SrsFormat* fo
|
|||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
if (format->is_aac_sequence_header()) {
|
||||
return refresh_init_mp4(shared_audio, format);
|
||||
}
|
||||
|
||||
if ((ret = refresh_mpd(format)) != ERROR_SUCCESS) {
|
||||
srs_error("DASH: Refresh the MPD failed. ret=%d", ret);
|
||||
return ret;
|
||||
|
@ -180,6 +194,10 @@ int SrsDashController::on_video(SrsSharedPtrMessage* shared_video, SrsFormat* fo
|
|||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
if (format->is_avc_sequence_header()) {
|
||||
return refresh_init_mp4(shared_video, format);
|
||||
}
|
||||
|
||||
if ((ret = refresh_mpd(format)) != ERROR_SUCCESS) {
|
||||
srs_error("DASH: Refresh the MPD failed. ret=%d", ret);
|
||||
return ret;
|
||||
|
@ -204,6 +222,278 @@ int SrsDashController::refresh_mpd(SrsFormat* format)
|
|||
return ret;
|
||||
}
|
||||
|
||||
int SrsDashController::refresh_init_mp4(SrsSharedPtrMessage* msg, SrsFormat* format)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
if (msg->size <= 0 || (msg->is_video() && !format->vcodec->avc_extra_size)
|
||||
|| (msg->is_audio() && !format->acodec->aac_extra_size)) {
|
||||
srs_warn("DASH: Ignore empty sequence header.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
string full_home = home + "/" + req->app + "/" + req->stream;
|
||||
if ((ret = srs_create_dir_recursively(full_home)) != ERROR_SUCCESS) {
|
||||
srs_error("DASH: Create media home failed, home=%s, ret=%d", full_home.c_str(), ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string path = full_home;
|
||||
if (msg->is_video()) {
|
||||
path += "/video-init.mp4";
|
||||
} else {
|
||||
path += "/audio-init.mp4";
|
||||
}
|
||||
|
||||
SrsFileWriter* fw = new SrsFileWriter();
|
||||
SrsAutoFree(SrsFileWriter, fw);
|
||||
|
||||
string path_tmp = path + ".tmp";
|
||||
if ((ret = fw->open(path_tmp)) != ERROR_SUCCESS) {
|
||||
srs_error("DASH: Open media failed, path=%s, ret=%d", path_tmp.c_str(), ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Write ftyp box.
|
||||
SrsMp4FileTypeBox* ftyp = new SrsMp4FileTypeBox();
|
||||
SrsAutoFree(SrsMp4FileTypeBox, ftyp);
|
||||
if (true) {
|
||||
ftyp->major_brand = SrsMp4BoxBrandISO5;
|
||||
ftyp->minor_version = 0;
|
||||
ftyp->set_compatible_brands(SrsMp4BoxBrandISOM, SrsMp4BoxBrandISO5, SrsMp4BoxBrandDASH, SrsMp4BoxBrandMP42);
|
||||
}
|
||||
|
||||
// Write moov.
|
||||
SrsMp4MovieBox* moov = new SrsMp4MovieBox();
|
||||
SrsAutoFree(SrsMp4MovieBox, moov);
|
||||
if (true) {
|
||||
SrsMp4MovieHeaderBox* mvhd = new SrsMp4MovieHeaderBox();
|
||||
moov->set_mvhd(mvhd);
|
||||
|
||||
mvhd->timescale = 1000; // Use tbn ms.
|
||||
mvhd->duration_in_tbn = 0;
|
||||
mvhd->next_track_ID = (msg->is_video()? video_tack_id : audio_track_id);
|
||||
|
||||
if (msg->is_video()) {
|
||||
SrsMp4TrackBox* trak = new SrsMp4TrackBox();
|
||||
moov->add_trak(trak);
|
||||
|
||||
SrsMp4TrackHeaderBox* tkhd = new SrsMp4TrackHeaderBox();
|
||||
trak->set_tkhd(tkhd);
|
||||
|
||||
tkhd->track_ID = mvhd->next_track_ID++;
|
||||
tkhd->duration = 0;
|
||||
tkhd->width = (format->vcodec->width << 16);
|
||||
tkhd->height = (format->vcodec->height << 16);
|
||||
|
||||
SrsMp4MediaBox* mdia = new SrsMp4MediaBox();
|
||||
trak->set_mdia(mdia);
|
||||
|
||||
SrsMp4MediaHeaderBox* mdhd = new SrsMp4MediaHeaderBox();
|
||||
mdia->set_mdhd(mdhd);
|
||||
|
||||
mdhd->timescale = 1000;
|
||||
mdhd->duration = 0;
|
||||
mdhd->set_language0('u');
|
||||
mdhd->set_language1('n');
|
||||
mdhd->set_language2('d');
|
||||
|
||||
SrsMp4HandlerReferenceBox* hdlr = new SrsMp4HandlerReferenceBox();
|
||||
mdia->set_hdlr(hdlr);
|
||||
|
||||
hdlr->handler_type = SrsMp4HandlerTypeVIDE;
|
||||
hdlr->name = "VideoHandler";
|
||||
|
||||
SrsMp4MediaInformationBox* minf = new SrsMp4MediaInformationBox();
|
||||
mdia->set_minf(minf);
|
||||
|
||||
SrsMp4VideoMeidaHeaderBox* vmhd = new SrsMp4VideoMeidaHeaderBox();
|
||||
minf->set_vmhd(vmhd);
|
||||
|
||||
SrsMp4DataInformationBox* dinf = new SrsMp4DataInformationBox();
|
||||
minf->set_dinf(dinf);
|
||||
|
||||
SrsMp4DataReferenceBox* dref = new SrsMp4DataReferenceBox();
|
||||
dinf->set_dref(dref);
|
||||
|
||||
SrsMp4DataEntryBox* url = new SrsMp4DataEntryUrlBox();
|
||||
dref->append(url);
|
||||
|
||||
SrsMp4SampleTableBox* stbl = new SrsMp4SampleTableBox();
|
||||
minf->set_stbl(stbl);
|
||||
|
||||
SrsMp4SampleDescriptionBox* stsd = new SrsMp4SampleDescriptionBox();
|
||||
stbl->set_stsd(stsd);
|
||||
|
||||
SrsMp4VisualSampleEntry* avc1 = new SrsMp4VisualSampleEntry();
|
||||
stsd->append(avc1);
|
||||
|
||||
avc1->width = format->vcodec->width;
|
||||
avc1->height = format->vcodec->height;
|
||||
|
||||
SrsMp4AvccBox* avcC = new SrsMp4AvccBox();
|
||||
avc1->set_avcC(avcC);
|
||||
|
||||
avcC->nb_config = format->vcodec->avc_extra_size;
|
||||
avcC->avc_config = new uint8_t[format->vcodec->avc_extra_size];
|
||||
memcpy(avcC->avc_config, format->vcodec->avc_extra_data, format->vcodec->avc_extra_size);
|
||||
|
||||
SrsMp4DecodingTime2SampleBox* stts = new SrsMp4DecodingTime2SampleBox();
|
||||
stbl->set_stts(stts);
|
||||
|
||||
SrsMp4Sample2ChunkBox* stsc = new SrsMp4Sample2ChunkBox();
|
||||
stbl->set_stsc(stsc);
|
||||
|
||||
SrsMp4SampleSizeBox* stsz = new SrsMp4SampleSizeBox();
|
||||
stbl->set_stsz(stsz);
|
||||
|
||||
SrsMp4ChunkOffsetBox* stco = new SrsMp4ChunkOffsetBox();
|
||||
stbl->set_stco(stco);
|
||||
|
||||
SrsMp4MovieExtendsBox* mvex = new SrsMp4MovieExtendsBox();
|
||||
moov->set_mvex(mvex);
|
||||
|
||||
SrsMp4TrackExtendsBox* trex = new SrsMp4TrackExtendsBox();
|
||||
mvex->set_trex(trex);
|
||||
|
||||
trex->track_ID = video_tack_id;
|
||||
trex->default_sample_description_index = 1;
|
||||
} else {
|
||||
SrsMp4TrackBox* trak = new SrsMp4TrackBox();
|
||||
moov->add_trak(trak);
|
||||
|
||||
SrsMp4TrackHeaderBox* tkhd = new SrsMp4TrackHeaderBox();
|
||||
tkhd->volume = 0x0100;
|
||||
trak->set_tkhd(tkhd);
|
||||
|
||||
tkhd->track_ID = mvhd->next_track_ID++;
|
||||
tkhd->duration = 0;
|
||||
|
||||
SrsMp4MediaBox* mdia = new SrsMp4MediaBox();
|
||||
trak->set_mdia(mdia);
|
||||
|
||||
SrsMp4MediaHeaderBox* mdhd = new SrsMp4MediaHeaderBox();
|
||||
mdia->set_mdhd(mdhd);
|
||||
|
||||
mdhd->timescale = 1000;
|
||||
mdhd->duration = 0;
|
||||
mdhd->set_language0('u');
|
||||
mdhd->set_language1('n');
|
||||
mdhd->set_language2('d');
|
||||
|
||||
SrsMp4HandlerReferenceBox* hdlr = new SrsMp4HandlerReferenceBox();
|
||||
mdia->set_hdlr(hdlr);
|
||||
|
||||
hdlr->handler_type = SrsMp4HandlerTypeSOUN;
|
||||
hdlr->name = "SoundHandler";
|
||||
|
||||
SrsMp4MediaInformationBox* minf = new SrsMp4MediaInformationBox();
|
||||
mdia->set_minf(minf);
|
||||
|
||||
SrsMp4SoundMeidaHeaderBox* smhd = new SrsMp4SoundMeidaHeaderBox();
|
||||
minf->set_smhd(smhd);
|
||||
|
||||
SrsMp4DataInformationBox* dinf = new SrsMp4DataInformationBox();
|
||||
minf->set_dinf(dinf);
|
||||
|
||||
SrsMp4DataReferenceBox* dref = new SrsMp4DataReferenceBox();
|
||||
dinf->set_dref(dref);
|
||||
|
||||
SrsMp4DataEntryBox* url = new SrsMp4DataEntryUrlBox();
|
||||
dref->append(url);
|
||||
|
||||
SrsMp4SampleTableBox* stbl = new SrsMp4SampleTableBox();
|
||||
minf->set_stbl(stbl);
|
||||
|
||||
SrsMp4SampleDescriptionBox* stsd = new SrsMp4SampleDescriptionBox();
|
||||
stbl->set_stsd(stsd);
|
||||
|
||||
SrsMp4AudioSampleEntry* mp4a = new SrsMp4AudioSampleEntry();
|
||||
mp4a->samplerate = uint32_t(srs_flv_srates[format->acodec->sound_rate]) << 16;
|
||||
if (format->acodec->sound_size == SrsAudioSampleBits16bit) {
|
||||
mp4a->samplesize = 16;
|
||||
} else {
|
||||
mp4a->samplesize = 8;
|
||||
}
|
||||
if (format->acodec->sound_type == SrsAudioChannelsStereo) {
|
||||
mp4a->channelcount = 2;
|
||||
} else {
|
||||
mp4a->channelcount = 1;
|
||||
}
|
||||
stsd->append(mp4a);
|
||||
|
||||
SrsMp4EsdsBox* esds = new SrsMp4EsdsBox();
|
||||
mp4a->set_esds(esds);
|
||||
|
||||
SrsMp4ES_Descriptor* es = esds->es;
|
||||
es->ES_ID = 0x02;
|
||||
|
||||
SrsMp4DecoderConfigDescriptor& desc = es->decConfigDescr;
|
||||
desc.objectTypeIndication = SrsMp4ObjectTypeAac;
|
||||
desc.streamType = SrsMp4StreamTypeAudioStream;
|
||||
srs_freep(desc.decSpecificInfo);
|
||||
|
||||
SrsMp4DecoderSpecificInfo* asc = new SrsMp4DecoderSpecificInfo();
|
||||
desc.decSpecificInfo = asc;
|
||||
asc->nb_asc = format->acodec->aac_extra_size;
|
||||
asc->asc = new uint8_t[format->acodec->aac_extra_size];
|
||||
memcpy(asc->asc, format->acodec->aac_extra_data, format->acodec->aac_extra_size);
|
||||
|
||||
SrsMp4DecodingTime2SampleBox* stts = new SrsMp4DecodingTime2SampleBox();
|
||||
stbl->set_stts(stts);
|
||||
|
||||
SrsMp4Sample2ChunkBox* stsc = new SrsMp4Sample2ChunkBox();
|
||||
stbl->set_stsc(stsc);
|
||||
|
||||
SrsMp4SampleSizeBox* stsz = new SrsMp4SampleSizeBox();
|
||||
stbl->set_stsz(stsz);
|
||||
|
||||
SrsMp4ChunkOffsetBox* stco = new SrsMp4ChunkOffsetBox();
|
||||
stbl->set_stco(stco);
|
||||
|
||||
SrsMp4MovieExtendsBox* mvex = new SrsMp4MovieExtendsBox();
|
||||
moov->set_mvex(mvex);
|
||||
|
||||
SrsMp4TrackExtendsBox* trex = new SrsMp4TrackExtendsBox();
|
||||
mvex->set_trex(trex);
|
||||
|
||||
trex->track_ID = audio_track_id;
|
||||
trex->default_sample_description_index = 1;
|
||||
}
|
||||
}
|
||||
|
||||
int nb_data = ftyp->nb_bytes() + moov->nb_bytes();
|
||||
uint8_t* data = new uint8_t[nb_data];
|
||||
SrsAutoFreeA(uint8_t, data);
|
||||
|
||||
SrsBuffer* buffer = new SrsBuffer();
|
||||
SrsAutoFree(SrsBuffer, buffer);
|
||||
if ((ret = buffer->initialize((char*)data, nb_data)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((ret = ftyp->encode(buffer)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
if ((ret = moov->encode(buffer)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((ret = fw->write(data, nb_data, NULL)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (::rename(path_tmp.c_str(), path.c_str()) < 0) {
|
||||
ret = ERROR_DASH_WRITE_FAILED;
|
||||
srs_error("DASH: Rename %s to %s failed, ret=%d", path_tmp.c_str(), path.c_str(), ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
srs_trace("DASH: Refresh media success, file=%s", path.c_str());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
SrsDash::SrsDash()
|
||||
{
|
||||
hub = NULL;
|
||||
|
|
|
@ -80,7 +80,12 @@ public:
|
|||
class SrsDashController
|
||||
{
|
||||
private:
|
||||
SrsRequest* req;
|
||||
SrsMpdWriter* mpd;
|
||||
private:
|
||||
std::string home;
|
||||
int video_tack_id;
|
||||
int audio_track_id;
|
||||
public:
|
||||
SrsDashController();
|
||||
virtual ~SrsDashController();
|
||||
|
@ -90,6 +95,7 @@ public:
|
|||
virtual int on_video(SrsSharedPtrMessage* shared_video, SrsFormat* format);
|
||||
private:
|
||||
virtual int refresh_mpd(SrsFormat* format);
|
||||
virtual int refresh_init_mp4(SrsSharedPtrMessage* msg, SrsFormat* format);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -560,7 +560,8 @@ int SrsFormat::on_audio(int64_t timestamp, char* data, int size)
|
|||
}
|
||||
|
||||
// @see: E.4.2 Audio Tags, video_file_format_spec_v10_1.pdf, page 76
|
||||
SrsAudioCodecId codec = (SrsAudioCodecId)((buffer->read_1bytes() >> 4) & 0x0f);
|
||||
uint8_t v = buffer->read_1bytes();
|
||||
SrsAudioCodecId codec = (SrsAudioCodecId)((v >> 4) & 0x0f);
|
||||
|
||||
if (codec != SrsAudioCodecIdMP3 && codec != SrsAudioCodecIdAAC) {
|
||||
return ret;
|
||||
|
@ -1361,6 +1362,21 @@ int SrsFormat::audio_mp3_demux(SrsBuffer* stream, int64_t timestamp)
|
|||
audio->cts = 0;
|
||||
audio->dts = timestamp;
|
||||
|
||||
// @see: E.4.2 Audio Tags, video_file_format_spec_v10_1.pdf, page 76
|
||||
int8_t sound_format = stream->read_1bytes();
|
||||
|
||||
int8_t sound_type = sound_format & 0x01;
|
||||
int8_t sound_size = (sound_format >> 1) & 0x01;
|
||||
int8_t sound_rate = (sound_format >> 2) & 0x03;
|
||||
sound_format = (sound_format >> 4) & 0x0f;
|
||||
|
||||
SrsAudioCodecId codec_id = (SrsAudioCodecId)sound_format;
|
||||
acodec->id = codec_id;
|
||||
|
||||
acodec->sound_type = (SrsAudioChannels)sound_type;
|
||||
acodec->sound_rate = (SrsAudioSampleRate)sound_rate;
|
||||
acodec->sound_size = (SrsAudioSampleBits)sound_size;
|
||||
|
||||
// we always decode aac then mp3.
|
||||
srs_assert(acodec->id == SrsAudioCodecIdMP3);
|
||||
|
||||
|
|
|
@ -515,14 +515,17 @@ public:
|
|||
*/
|
||||
class SrsAudioCodecConfig : public SrsCodecConfig
|
||||
{
|
||||
// In FLV specification.
|
||||
public:
|
||||
// audio specified
|
||||
SrsAudioCodecId id;
|
||||
// audio aac specified.
|
||||
SrsAudioSampleRate sound_rate;
|
||||
SrsAudioSampleBits sound_size;
|
||||
// TODO: FIXME: Rename to sound_channels.
|
||||
SrsAudioChannels sound_type;
|
||||
int audio_data_rate; // in bps
|
||||
// In AAC specification.
|
||||
public:
|
||||
/**
|
||||
* audio specified
|
||||
|
@ -539,6 +542,7 @@ public:
|
|||
* channelConfiguration
|
||||
*/
|
||||
uint8_t aac_channels;
|
||||
// Sequence header payload.
|
||||
public:
|
||||
/**
|
||||
* the aac extra data, the AAC sequence header,
|
||||
|
|
|
@ -226,6 +226,8 @@ int SrsMp4Box::discovery(SrsBuffer* buf, SrsMp4Box** ppbox)
|
|||
case SrsMp4BoxTypeMP4A: box = new SrsMp4AudioSampleEntry(); break;
|
||||
case SrsMp4BoxTypeESDS: box = new SrsMp4EsdsBox(); break;
|
||||
case SrsMp4BoxTypeUDTA: box = new SrsMp4UserDataBox(); break;
|
||||
case SrsMp4BoxTypeMVEX: box = new SrsMp4MovieExtendsBox(); break;
|
||||
case SrsMp4BoxTypeTREX: box = new SrsMp4TrackExtendsBox(); break;
|
||||
default:
|
||||
ret = ERROR_MP4_BOX_ILLEGAL_TYPE;
|
||||
srs_error("MP4 illegal box type=%d. ret=%d", type, ret);
|
||||
|
@ -690,7 +692,19 @@ SrsMp4MovieHeaderBox* SrsMp4MovieBox::mvhd()
|
|||
void SrsMp4MovieBox::set_mvhd(SrsMp4MovieHeaderBox* v)
|
||||
{
|
||||
remove(SrsMp4BoxTypeMVHD);
|
||||
boxes.insert(boxes.begin(), v);
|
||||
boxes.push_back(v);
|
||||
}
|
||||
|
||||
SrsMp4MovieExtendsBox* SrsMp4MovieBox::mvex()
|
||||
{
|
||||
SrsMp4Box* box = get(SrsMp4BoxTypeMVEX);
|
||||
return dynamic_cast<SrsMp4MovieExtendsBox*>(box);
|
||||
}
|
||||
|
||||
void SrsMp4MovieBox::set_mvex(SrsMp4MovieExtendsBox* v)
|
||||
{
|
||||
remove(SrsMp4BoxTypeMVEX);
|
||||
boxes.push_back(v);
|
||||
}
|
||||
|
||||
SrsMp4TrackBox* SrsMp4MovieBox::video()
|
||||
|
@ -884,6 +898,77 @@ int SrsMp4MovieHeaderBox::decode_header(SrsBuffer* buf)
|
|||
return ret;
|
||||
}
|
||||
|
||||
SrsMp4MovieExtendsBox::SrsMp4MovieExtendsBox()
|
||||
{
|
||||
type = SrsMp4BoxTypeMVEX;
|
||||
}
|
||||
|
||||
SrsMp4MovieExtendsBox::~SrsMp4MovieExtendsBox()
|
||||
{
|
||||
}
|
||||
|
||||
SrsMp4TrackExtendsBox* SrsMp4MovieExtendsBox::trex()
|
||||
{
|
||||
SrsMp4Box* box = get(SrsMp4BoxTypeTREX);
|
||||
return dynamic_cast<SrsMp4TrackExtendsBox*>(box);
|
||||
}
|
||||
|
||||
void SrsMp4MovieExtendsBox::set_trex(SrsMp4TrackExtendsBox* v)
|
||||
{
|
||||
remove(SrsMp4BoxTypeTREX);
|
||||
boxes.push_back(v);
|
||||
}
|
||||
|
||||
SrsMp4TrackExtendsBox::SrsMp4TrackExtendsBox()
|
||||
{
|
||||
type = SrsMp4BoxTypeTREX;
|
||||
track_ID = default_sample_size = default_sample_flags = 0;
|
||||
default_sample_size = default_sample_duration = default_sample_description_index = 0;
|
||||
}
|
||||
|
||||
SrsMp4TrackExtendsBox::~SrsMp4TrackExtendsBox()
|
||||
{
|
||||
}
|
||||
|
||||
int SrsMp4TrackExtendsBox::nb_header()
|
||||
{
|
||||
return SrsMp4FullBox::nb_header() + 4*5;
|
||||
}
|
||||
|
||||
int SrsMp4TrackExtendsBox::encode_header(SrsBuffer* buf)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
if ((ret = SrsMp4FullBox::encode_header(buf)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
buf->write_4bytes(track_ID);
|
||||
buf->write_4bytes(default_sample_description_index);
|
||||
buf->write_4bytes(default_sample_duration);
|
||||
buf->write_4bytes(default_sample_size);
|
||||
buf->write_4bytes(default_sample_flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsMp4TrackExtendsBox::decode_header(SrsBuffer* buf)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
if ((ret = SrsMp4FullBox::decode_header(buf)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
track_ID = buf->read_4bytes();
|
||||
default_sample_description_index = buf->read_4bytes();
|
||||
default_sample_duration = buf->read_4bytes();
|
||||
default_sample_size = buf->read_4bytes();
|
||||
default_sample_flags = buf->read_4bytes();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
SrsMp4TrackBox::SrsMp4TrackBox()
|
||||
{
|
||||
type = SrsMp4BoxTypeTRAK;
|
||||
|
@ -4010,7 +4095,8 @@ int SrsMp4Decoder::parse_ftyp(SrsMp4FileTypeBox* ftyp)
|
|||
// File Type Box (ftyp)
|
||||
bool legal_brand = false;
|
||||
static SrsMp4BoxBrand legal_brands[] = {
|
||||
SrsMp4BoxBrandISOM, SrsMp4BoxBrandISO2, SrsMp4BoxBrandAVC1, SrsMp4BoxBrandMP41
|
||||
SrsMp4BoxBrandISOM, SrsMp4BoxBrandISO2, SrsMp4BoxBrandAVC1, SrsMp4BoxBrandMP41,
|
||||
SrsMp4BoxBrandISO5
|
||||
};
|
||||
for (int i = 0; i < sizeof(legal_brands)/sizeof(SrsMp4BoxBrand); i++) {
|
||||
if (ftyp->major_brand == legal_brands[i]) {
|
||||
|
@ -4375,7 +4461,7 @@ int SrsMp4Encoder::flush()
|
|||
|
||||
mvhd->timescale = 1000; // Use tbn ms.
|
||||
mvhd->duration_in_tbn = srs_max(vduration, aduration);
|
||||
mvhd->next_track_ID++;
|
||||
mvhd->next_track_ID = 1; // Starts from 1, increase when use it.
|
||||
|
||||
if (nb_videos) {
|
||||
SrsMp4TrackBox* trak = new SrsMp4TrackBox();
|
||||
|
|
|
@ -64,6 +64,8 @@ class SrsMp4VideoMeidaHeaderBox;
|
|||
class SrsMp4DataInformationBox;
|
||||
class SrsMp4DataReferenceBox;
|
||||
class SrsMp4SoundMeidaHeaderBox;
|
||||
class SrsMp4MovieExtendsBox;
|
||||
class SrsMp4TrackExtendsBox;
|
||||
|
||||
/**
|
||||
* 4.2 Object Structure
|
||||
|
@ -109,6 +111,8 @@ enum SrsMp4BoxType
|
|||
SrsMp4BoxTypeMP4A = 0x6d703461, // 'mp4a'
|
||||
SrsMp4BoxTypeESDS = 0x65736473, // 'esds'
|
||||
SrsMp4BoxTypeUDTA = 0x75647461, // 'udta'
|
||||
SrsMp4BoxTypeMVEX = 0x6d766578, // 'mvex'
|
||||
SrsMp4BoxTypeTREX = 0x74726578, // 'trex'
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -134,6 +138,9 @@ enum SrsMp4BoxBrand
|
|||
SrsMp4BoxBrandISO2 = 0x69736f32, // 'iso2'
|
||||
SrsMp4BoxBrandAVC1 = 0x61766331, // 'avc1'
|
||||
SrsMp4BoxBrandMP41 = 0x6d703431, // 'mp41'
|
||||
SrsMp4BoxBrandISO5 = 0x69736f35, // 'iso5'
|
||||
SrsMp4BoxBrandMP42 = 0x6d703432, // 'mp42'
|
||||
SrsMp4BoxBrandDASH = 0x64617368, // 'dash'
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -321,6 +328,9 @@ public:
|
|||
// Get the header of moov.
|
||||
virtual SrsMp4MovieHeaderBox* mvhd();
|
||||
virtual void set_mvhd(SrsMp4MovieHeaderBox* v);
|
||||
// Get the movie extends header.
|
||||
virtual SrsMp4MovieExtendsBox* mvex();
|
||||
virtual void set_mvex(SrsMp4MovieExtendsBox* v);
|
||||
// Get the first video track.
|
||||
virtual SrsMp4TrackBox* video();
|
||||
// Get the first audio track.
|
||||
|
@ -395,6 +405,47 @@ enum SrsMp4TrackType
|
|||
SrsMp4TrackTypeVideo = 0x02,
|
||||
};
|
||||
|
||||
/**
|
||||
* 8.8.1 Movie Extends Box (mvex)
|
||||
* ISO_IEC_14496-12-base-format-2012.pdf, page 64
|
||||
* This box warns readers that there might be Movie Fragment Boxes in this file. To know of all samples in the
|
||||
* tracks, these Movie Fragment Boxes must be found and scanned in order, and their information logically
|
||||
* added to that found in the Movie Box.
|
||||
*/
|
||||
class SrsMp4MovieExtendsBox : public SrsMp4Box
|
||||
{
|
||||
public:
|
||||
SrsMp4MovieExtendsBox();
|
||||
virtual ~SrsMp4MovieExtendsBox();
|
||||
public:
|
||||
// Get the track extends box.
|
||||
virtual SrsMp4TrackExtendsBox* trex();
|
||||
virtual void set_trex(SrsMp4TrackExtendsBox* v);
|
||||
};
|
||||
|
||||
/**
|
||||
* 8.8.3 Track Extends Box(trex)
|
||||
* ISO_IEC_14496-12-base-format-2012.pdf, page 65
|
||||
*/
|
||||
class SrsMp4TrackExtendsBox : public SrsMp4FullBox
|
||||
{
|
||||
public:
|
||||
// identifies the track; this shall be the track ID of a track in the Movie Box
|
||||
uint32_t track_ID;
|
||||
// these fields set up defaults used in the track fragments.
|
||||
uint32_t default_sample_description_index;
|
||||
uint32_t default_sample_duration;
|
||||
uint32_t default_sample_size;
|
||||
uint32_t default_sample_flags;
|
||||
public:
|
||||
SrsMp4TrackExtendsBox();
|
||||
virtual ~SrsMp4TrackExtendsBox();
|
||||
protected:
|
||||
virtual int nb_header();
|
||||
virtual int encode_header(SrsBuffer* buf);
|
||||
virtual int decode_header(SrsBuffer* buf);
|
||||
};
|
||||
|
||||
/**
|
||||
* 8.3.1 Track Box (trak)
|
||||
* ISO_IEC_14496-12-base-format-2012.pdf, page 32
|
||||
|
|
Loading…
Reference in a new issue