mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
for #738, use reader and seeker for mp4 demuxer to seek for general mp4(ftyp-mdat-moov).
This commit is contained in:
parent
bbee16e4db
commit
9d21a8bb33
16 changed files with 237 additions and 101 deletions
|
@ -280,7 +280,7 @@ void SrsHttpFileReader::skip(int64_t /*size*/)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t SrsHttpFileReader::lseek(int64_t offset)
|
int64_t SrsHttpFileReader::seek2(int64_t offset)
|
||||||
{
|
{
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
@ -324,4 +324,10 @@ int SrsHttpFileReader::read(void* buf, size_t count, ssize_t* pnread)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int SrsHttpFileReader::lseek(off_t offset, int whence, off_t* seeked)
|
||||||
|
{
|
||||||
|
// TODO: FIXME: Use HTTP range for seek.
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -120,14 +120,11 @@ public:
|
||||||
virtual bool is_open();
|
virtual bool is_open();
|
||||||
virtual int64_t tellg();
|
virtual int64_t tellg();
|
||||||
virtual void skip(int64_t size);
|
virtual void skip(int64_t size);
|
||||||
virtual int64_t lseek(int64_t offset);
|
virtual int64_t seek2(int64_t offset);
|
||||||
virtual int64_t filesize();
|
virtual int64_t filesize();
|
||||||
public:
|
public:
|
||||||
/**
|
|
||||||
* read from file.
|
|
||||||
* @param pnread the output nb_read, NULL to ignore.
|
|
||||||
*/
|
|
||||||
virtual int read(void* buf, size_t count, ssize_t* pnread);
|
virtual int read(void* buf, size_t count, ssize_t* pnread);
|
||||||
|
virtual int lseek(off_t offset, int whence, off_t* seeked);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -370,7 +370,7 @@ int SrsFlvSegment::update_flv_metadata()
|
||||||
}
|
}
|
||||||
|
|
||||||
// update the flesize.
|
// update the flesize.
|
||||||
fs->lseek(filesize_offset);
|
fs->seek2(filesize_offset);
|
||||||
if ((ret = fs->write(buf, SrsAmf0Size::number(), NULL)) != ERROR_SUCCESS) {
|
if ((ret = fs->write(buf, SrsAmf0Size::number(), NULL)) != ERROR_SUCCESS) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -385,13 +385,13 @@ int SrsFlvSegment::update_flv_metadata()
|
||||||
}
|
}
|
||||||
|
|
||||||
// update the duration
|
// update the duration
|
||||||
fs->lseek(duration_offset);
|
fs->seek2(duration_offset);
|
||||||
if ((ret = fs->write(buf, SrsAmf0Size::number(), NULL)) != ERROR_SUCCESS) {
|
if ((ret = fs->write(buf, SrsAmf0Size::number(), NULL)) != ERROR_SUCCESS) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset the offset.
|
// reset the offset.
|
||||||
fs->lseek(cur);
|
fs->seek2(cur);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,7 +131,7 @@ int SrsVodStream::serve_flv_stream(ISrsHttpResponseWriter* w, ISrsHttpMessage* r
|
||||||
}
|
}
|
||||||
|
|
||||||
// write body.
|
// write body.
|
||||||
if ((ret = ffd.lseek(offset)) != ERROR_SUCCESS) {
|
if ((ret = ffd.seek2(offset)) != ERROR_SUCCESS) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,7 +186,7 @@ int SrsVodStream::serve_mp4_stream(ISrsHttpResponseWriter* w, ISrsHttpMessage* r
|
||||||
w->header()->set("Content-Range", content_range.str());
|
w->header()->set("Content-Range", content_range.str());
|
||||||
|
|
||||||
// write body.
|
// write body.
|
||||||
fs.lseek(start);
|
fs.seek2(start);
|
||||||
|
|
||||||
// send data
|
// send data
|
||||||
if ((ret = copy(w, &fs, r, (int)left)) != ERROR_SUCCESS) {
|
if ((ret = copy(w, &fs, r, (int)left)) != ERROR_SUCCESS) {
|
||||||
|
|
|
@ -248,9 +248,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#define ERROR_MP4_BOX_ILLEGAL_SCHEMA 3072
|
#define ERROR_MP4_BOX_ILLEGAL_SCHEMA 3072
|
||||||
#define ERROR_MP4_BOX_STRING 3073
|
#define ERROR_MP4_BOX_STRING 3073
|
||||||
#define ERROR_MP4_BOX_ILLEGAL_BRAND 3074
|
#define ERROR_MP4_BOX_ILLEGAL_BRAND 3074
|
||||||
#define ERROR_MP4_NOT_NON_SEEKABLE 3075
|
#define ERROR_MP4_ESDS_SL_Config 3075
|
||||||
#define ERROR_MP4_ESDS_SL_Config 3076
|
#define ERROR_MP4_ILLEGAL_MOOV 3076
|
||||||
#define ERROR_MP4_ILLEGAL_MOOV 3077
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////
|
||||||
// HTTP/StreamCaster/KAFKA protocol error.
|
// HTTP/StreamCaster/KAFKA protocol error.
|
||||||
|
|
|
@ -117,7 +117,7 @@ bool SrsFileWriter::is_open()
|
||||||
return fd > 0;
|
return fd > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SrsFileWriter::lseek(int64_t offset)
|
void SrsFileWriter::seek2(int64_t offset)
|
||||||
{
|
{
|
||||||
::lseek(fd, (off_t)offset, SEEK_SET);
|
::lseek(fd, (off_t)offset, SEEK_SET);
|
||||||
}
|
}
|
||||||
|
@ -167,6 +167,19 @@ int SrsFileWriter::writev(const iovec* iov, int iovcnt, ssize_t* pnwrite)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int SrsFileWriter::lseek(off_t offset, int whence, off_t* seeked)
|
||||||
|
{
|
||||||
|
off_t sk = ::lseek(fd, offset, whence);
|
||||||
|
if (sk < 0) {
|
||||||
|
return ERROR_SYSTEM_FILE_SEEK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (seeked) {
|
||||||
|
*seeked = sk;
|
||||||
|
}
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
SrsFileReader::SrsFileReader()
|
SrsFileReader::SrsFileReader()
|
||||||
{
|
{
|
||||||
fd = -1;
|
fd = -1;
|
||||||
|
@ -231,7 +244,7 @@ void SrsFileReader::skip(int64_t size)
|
||||||
::lseek(fd, (off_t)size, SEEK_CUR);
|
::lseek(fd, (off_t)size, SEEK_CUR);
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t SrsFileReader::lseek(int64_t offset)
|
int64_t SrsFileReader::seek2(int64_t offset)
|
||||||
{
|
{
|
||||||
return (int64_t)::lseek(fd, (off_t)offset, SEEK_SET);
|
return (int64_t)::lseek(fd, (off_t)offset, SEEK_SET);
|
||||||
}
|
}
|
||||||
|
@ -268,3 +281,16 @@ int SrsFileReader::read(void* buf, size_t count, ssize_t* pnread)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int SrsFileReader::lseek(off_t offset, int whence, off_t* seeked)
|
||||||
|
{
|
||||||
|
off_t sk = ::lseek(fd, offset, whence);
|
||||||
|
if (sk < 0) {
|
||||||
|
return ERROR_SYSTEM_FILE_SEEK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (seeked) {
|
||||||
|
*seeked = sk;
|
||||||
|
}
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
/**
|
/**
|
||||||
* file writer, to write to file.
|
* file writer, to write to file.
|
||||||
*/
|
*/
|
||||||
class SrsFileWriter : public ISrsWriter
|
class SrsFileWriter : public ISrsWriteSeeker
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
std::string path;
|
std::string path;
|
||||||
|
@ -67,25 +67,19 @@ public:
|
||||||
virtual void close();
|
virtual void close();
|
||||||
public:
|
public:
|
||||||
virtual bool is_open();
|
virtual bool is_open();
|
||||||
virtual void lseek(int64_t offset);
|
virtual void seek2(int64_t offset);
|
||||||
virtual int64_t tellg();
|
virtual int64_t tellg();
|
||||||
|
// Interface ISrsWriteSeeker
|
||||||
public:
|
public:
|
||||||
/**
|
|
||||||
* write to file.
|
|
||||||
* @param pnwrite the output nb_write, NULL to ignore.
|
|
||||||
*/
|
|
||||||
virtual int write(void* buf, size_t count, ssize_t* pnwrite);
|
virtual int write(void* buf, size_t count, ssize_t* pnwrite);
|
||||||
/**
|
|
||||||
* for the HTTP FLV, to writev to improve performance.
|
|
||||||
* @see https://github.com/ossrs/srs/issues/405
|
|
||||||
*/
|
|
||||||
virtual int writev(const iovec* iov, int iovcnt, ssize_t* pnwrite);
|
virtual int writev(const iovec* iov, int iovcnt, ssize_t* pnwrite);
|
||||||
|
virtual int lseek(off_t offset, int whence, off_t* seeked);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* file reader, to read from file.
|
* file reader, to read from file.
|
||||||
*/
|
*/
|
||||||
class SrsFileReader : public ISrsReader
|
class SrsFileReader : public ISrsReadSeeker
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
std::string path;
|
std::string path;
|
||||||
|
@ -109,14 +103,12 @@ public:
|
||||||
virtual bool is_open();
|
virtual bool is_open();
|
||||||
virtual int64_t tellg();
|
virtual int64_t tellg();
|
||||||
virtual void skip(int64_t size);
|
virtual void skip(int64_t size);
|
||||||
virtual int64_t lseek(int64_t offset);
|
virtual int64_t seek2(int64_t offset);
|
||||||
virtual int64_t filesize();
|
virtual int64_t filesize();
|
||||||
|
// Interface ISrsReadSeeker
|
||||||
public:
|
public:
|
||||||
/**
|
|
||||||
* read from file.
|
|
||||||
* @param pnread the output nb_read, NULL to ignore.
|
|
||||||
*/
|
|
||||||
virtual int read(void* buf, size_t count, ssize_t* pnread);
|
virtual int read(void* buf, size_t count, ssize_t* pnread);
|
||||||
|
virtual int lseek(off_t offset, int whence, off_t* seeked);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -949,7 +949,7 @@ int SrsFlvVodStreamDecoder::read_sequence_header_summary(int64_t* pstart, int* p
|
||||||
|
|
||||||
// seek to the sequence header start offset.
|
// seek to the sequence header start offset.
|
||||||
if (av_sequence_offset_start > 0) {
|
if (av_sequence_offset_start > 0) {
|
||||||
reader->lseek(av_sequence_offset_start);
|
reader->seek2(av_sequence_offset_start);
|
||||||
*pstart = av_sequence_offset_start;
|
*pstart = av_sequence_offset_start;
|
||||||
*psize = (int)(av_sequence_offset_end - av_sequence_offset_start);
|
*psize = (int)(av_sequence_offset_end - av_sequence_offset_start);
|
||||||
}
|
}
|
||||||
|
@ -957,7 +957,7 @@ int SrsFlvVodStreamDecoder::read_sequence_header_summary(int64_t* pstart, int* p
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsFlvVodStreamDecoder::lseek(int64_t offset)
|
int SrsFlvVodStreamDecoder::seek2(int64_t offset)
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
@ -969,7 +969,7 @@ int SrsFlvVodStreamDecoder::lseek(int64_t offset)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reader->lseek(offset) < 0) {
|
if (reader->seek2(offset) < 0) {
|
||||||
ret = ERROR_SYSTEM_FILE_SEEK;
|
ret = ERROR_SYSTEM_FILE_SEEK;
|
||||||
srs_warn("flv fast decoder seek error, "
|
srs_warn("flv fast decoder seek error, "
|
||||||
"size=%"PRId64", offset=%"PRId64", ret=%d",
|
"size=%"PRId64", offset=%"PRId64", ret=%d",
|
||||||
|
|
|
@ -597,7 +597,7 @@ public:
|
||||||
/**
|
/**
|
||||||
* for start offset, seed to this position and response flv stream.
|
* for start offset, seed to this position and response flv stream.
|
||||||
*/
|
*/
|
||||||
virtual int lseek(int64_t offset);
|
virtual int seek2(int64_t offset);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -31,6 +31,22 @@ ISrsReader::~ISrsReader()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ISrsSeeker::ISrsSeeker()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsSeeker::~ISrsSeeker()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsReadSeeker::ISrsReadSeeker()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsReadSeeker::~ISrsReadSeeker()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
ISrsStreamWriter::ISrsStreamWriter()
|
ISrsStreamWriter::ISrsStreamWriter()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -55,3 +71,11 @@ ISrsWriter::~ISrsWriter()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ISrsWriteSeeker::ISrsWriteSeeker()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsWriteSeeker::~ISrsWriteSeeker()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,37 @@ public:
|
||||||
virtual int read(void* buf, size_t size, ssize_t* nread) = 0;
|
virtual int read(void* buf, size_t size, ssize_t* nread) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The seeker to seek with a device.
|
||||||
|
*/
|
||||||
|
class ISrsSeeker
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ISrsSeeker();
|
||||||
|
virtual ~ISrsSeeker();
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* The lseek() function repositions the offset of the file descriptor fildes to the argument offset, according to the
|
||||||
|
* directive whence. lseek() repositions the file pointer fildes as follows:
|
||||||
|
* If whence is SEEK_SET, the offset is set to offset bytes.
|
||||||
|
* If whence is SEEK_CUR, the offset is set to its current location plus offset bytes.
|
||||||
|
* If whence is SEEK_END, the offset is set to the size of the file plus offset bytes.
|
||||||
|
* @param seeked Upon successful completion, lseek() returns the resulting offset location as measured in bytes from
|
||||||
|
* the beginning of the file. NULL to ignore.
|
||||||
|
*/
|
||||||
|
virtual int lseek(off_t offset, int whence, off_t* seeked) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The reader and seeker.
|
||||||
|
*/
|
||||||
|
class ISrsReadSeeker : virtual public ISrsReader, virtual public ISrsSeeker
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ISrsReadSeeker();
|
||||||
|
virtual ~ISrsReadSeeker();
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The writer to write stream data to channel.
|
* The writer to write stream data to channel.
|
||||||
*/
|
*/
|
||||||
|
@ -79,6 +110,8 @@ public:
|
||||||
/**
|
/**
|
||||||
* write iov over writer.
|
* write iov over writer.
|
||||||
* @nwrite the actual written bytes. NULL to ignore.
|
* @nwrite the actual written bytes. NULL to ignore.
|
||||||
|
* @remark for the HTTP FLV, to writev to improve performance.
|
||||||
|
* @see https://github.com/ossrs/srs/issues/405
|
||||||
*/
|
*/
|
||||||
virtual int writev(const iovec *iov, int iov_size, ssize_t* nwrite) = 0;
|
virtual int writev(const iovec *iov, int iov_size, ssize_t* nwrite) = 0;
|
||||||
};
|
};
|
||||||
|
@ -93,5 +126,15 @@ public:
|
||||||
virtual ~ISrsWriter();
|
virtual ~ISrsWriter();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The writer and seeker.
|
||||||
|
*/
|
||||||
|
class ISrsWriteSeeker : virtual public ISrsWriter, virtual public ISrsSeeker
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ISrsWriteSeeker();
|
||||||
|
virtual ~ISrsWriteSeeker();
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -2959,7 +2959,8 @@ int SrsMp4UserDataBox::decode_header(SrsBuffer* buf)
|
||||||
|
|
||||||
SrsMp4Decoder::SrsMp4Decoder()
|
SrsMp4Decoder::SrsMp4Decoder()
|
||||||
{
|
{
|
||||||
reader = NULL;
|
rsio = NULL;
|
||||||
|
brand = SrsMp4BoxBrandForbidden;
|
||||||
buf = new char[SRS_MP4_BUF_SIZE];
|
buf = new char[SRS_MP4_BUF_SIZE];
|
||||||
stream = new SrsSimpleStream();
|
stream = new SrsSimpleStream();
|
||||||
}
|
}
|
||||||
|
@ -2970,66 +2971,83 @@ SrsMp4Decoder::~SrsMp4Decoder()
|
||||||
srs_freep(stream);
|
srs_freep(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsMp4Decoder::initialize(ISrsReader* r)
|
int SrsMp4Decoder::initialize(ISrsReadSeeker* rs)
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
srs_assert(r);
|
srs_assert(rs);
|
||||||
reader = r;
|
rsio = rs;
|
||||||
|
|
||||||
// File Type Box (ftyp)
|
// For mdat before moov, we must reset the io.
|
||||||
if (true) {
|
off_t offset = -1;
|
||||||
SrsMp4Box* box = NULL;
|
|
||||||
SrsAutoFree(SrsMp4Box, box);
|
|
||||||
|
|
||||||
if ((ret = load_next_box(&box, SrsMp4BoxTypeFTYP)) != ERROR_SUCCESS) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
SrsMp4FileTypeBox* ftyp = dynamic_cast<SrsMp4FileTypeBox*>(box);
|
|
||||||
|
|
||||||
bool legal_brand = false;
|
|
||||||
static SrsMp4BoxBrand legal_brands[] = {
|
|
||||||
SrsMp4BoxBrandISOM, SrsMp4BoxBrandISO2, SrsMp4BoxBrandAVC1, SrsMp4BoxBrandMP41
|
|
||||||
};
|
|
||||||
for (int i = 0; i < sizeof(legal_brands)/sizeof(SrsMp4BoxBrand); i++) {
|
|
||||||
if (ftyp->major_brand == legal_brands[i]) {
|
|
||||||
legal_brand = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!legal_brand) {
|
|
||||||
ret = ERROR_MP4_BOX_ILLEGAL_BRAND;
|
|
||||||
srs_error("MP4 brand is illegal, brand=%d. ret=%d", ftyp->major_brand, ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Media Data Box (mdat) or Movie Box (moov)
|
|
||||||
SrsMp4Box* box = NULL;
|
|
||||||
SrsAutoFree(SrsMp4Box, box);
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
SrsMp4Box* box = NULL;
|
||||||
|
|
||||||
if ((ret = load_next_box(&box, 0)) != ERROR_SUCCESS) {
|
if ((ret = load_next_box(&box, 0)) != ERROR_SUCCESS) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!box->is_mdat() && !box->is_moov()) {
|
if (box->is_ftyp()) {
|
||||||
srs_freep(box);
|
SrsMp4FileTypeBox* ftyp = dynamic_cast<SrsMp4FileTypeBox*>(box);
|
||||||
continue;
|
if ((ret = parse_ftyp(ftyp)) != ERROR_SUCCESS) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
} else if (box->is_mdat()) {
|
||||||
|
off_t cur = 0;
|
||||||
|
if ((ret = rsio->lseek(0, SEEK_CUR, &cur)) != ERROR_SUCCESS) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
offset = off_t(cur - box->sz());
|
||||||
|
} else if (box->is_moov()) {
|
||||||
|
SrsMp4MovieBox* moov = dynamic_cast<SrsMp4MovieBox*>(box);
|
||||||
|
if ((ret = parse_moov(moov)) != ERROR_SUCCESS) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
srs_freep(box);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only support non-seek mp4, that is, mdat should never before moov.
|
if (brand == SrsMp4BoxBrandForbidden) {
|
||||||
// @see https://github.com/ossrs/srs/issues/738#issuecomment-276343669
|
ret = ERROR_MP4_BOX_ILLEGAL_SCHEMA;
|
||||||
if (box->is_mdat()) {
|
srs_error("MP4 missing ftyp. ret=%d", ret);
|
||||||
ret = ERROR_MP4_NOT_NON_SEEKABLE;
|
|
||||||
srs_error("MP4 is not non-seekable. ret=%d", ret);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the Movie Header Box(moov).
|
// Reset the io to the start to reparse the general MP4.
|
||||||
SrsMp4MovieBox* moov = dynamic_cast<SrsMp4MovieBox*>(box);
|
if (offset >= 0) {
|
||||||
return parse_moov(moov);
|
return rsio->lseek(offset, SEEK_SET, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsMp4Decoder::parse_ftyp(SrsMp4FileTypeBox* ftyp)
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
// File Type Box (ftyp)
|
||||||
|
bool legal_brand = false;
|
||||||
|
static SrsMp4BoxBrand legal_brands[] = {
|
||||||
|
SrsMp4BoxBrandISOM, SrsMp4BoxBrandISO2, SrsMp4BoxBrandAVC1, SrsMp4BoxBrandMP41
|
||||||
|
};
|
||||||
|
for (int i = 0; i < sizeof(legal_brands)/sizeof(SrsMp4BoxBrand); i++) {
|
||||||
|
if (ftyp->major_brand == legal_brands[i]) {
|
||||||
|
legal_brand = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!legal_brand) {
|
||||||
|
ret = ERROR_MP4_BOX_ILLEGAL_BRAND;
|
||||||
|
srs_error("MP4 brand is illegal, brand=%d. ret=%d", ftyp->major_brand, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
brand = ftyp->major_brand;
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsMp4Decoder::parse_moov(SrsMp4MovieBox* moov)
|
int SrsMp4Decoder::parse_moov(SrsMp4MovieBox* moov)
|
||||||
|
@ -3110,7 +3128,7 @@ int SrsMp4Decoder::do_load_next_box(SrsMp4Box** ppbox, uint32_t required_box_typ
|
||||||
uint64_t required = box? box->sz():4;
|
uint64_t required = box? box->sz():4;
|
||||||
while (stream->length() < required) {
|
while (stream->length() < required) {
|
||||||
ssize_t nread;
|
ssize_t nread;
|
||||||
if ((ret = reader->read(buf, SRS_MP4_BUF_SIZE, &nread)) != ERROR_SUCCESS) {
|
if ((ret = rsio->read(buf, SRS_MP4_BUF_SIZE, &nread)) != ERROR_SUCCESS) {
|
||||||
srs_error("MP4 load failed, nread=%d, required=%d. ret=%d", nread, required, ret);
|
srs_error("MP4 load failed, nread=%d, required=%d. ret=%d", nread, required, ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -3131,18 +3149,36 @@ int SrsMp4Decoder::do_load_next_box(SrsMp4Box** ppbox, uint32_t required_box_typ
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode util we can demux the whole box.
|
// For mdat, skip the content.
|
||||||
if (!buffer->require((int)box->sz())) {
|
if (box->is_mdat()) {
|
||||||
continue;
|
// Never load the mdat box content, instead we skip it, for it's too large.
|
||||||
}
|
// The demuxer use seeker to read sample one by one.
|
||||||
|
if (box->is_mdat()) {
|
||||||
|
int offset = (int)(box->sz() - stream->length());
|
||||||
|
if (offset < 0) {
|
||||||
|
stream->erase(stream->length() + offset);
|
||||||
|
} else {
|
||||||
|
stream->erase(stream->length());
|
||||||
|
}
|
||||||
|
if (offset > 0 && (ret = rsio->lseek(offset, SEEK_CUR, NULL)) != ERROR_SUCCESS) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Util we can demux the whole box.
|
||||||
|
if (!buffer->require((int)box->sz())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode the matched box or any box is matched.
|
||||||
|
if (!required_box_type || box->type == required_box_type) {
|
||||||
|
ret = box->decode(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
if (!required_box_type || box->type == required_box_type) {
|
// Remove the consumed bytes.
|
||||||
ret = box->decode(buffer);
|
stream->erase((int)box->sz());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the consumed bytes.
|
|
||||||
stream->erase((int)box->sz());
|
|
||||||
|
|
||||||
if (ret != ERROR_SUCCESS) {
|
if (ret != ERROR_SUCCESS) {
|
||||||
srs_freep(box);
|
srs_freep(box);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -35,7 +35,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class ISrsReader;
|
class ISrsReadSeeker;
|
||||||
class SrsMp4TrackBox;
|
class SrsMp4TrackBox;
|
||||||
class SrsMp4MediaBox;
|
class SrsMp4MediaBox;
|
||||||
class SrsSimpleStream;
|
class SrsSimpleStream;
|
||||||
|
@ -1342,8 +1342,12 @@ protected:
|
||||||
class SrsMp4Decoder
|
class SrsMp4Decoder
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
// Underlayer reader.
|
// The major brand of decoder, parse from ftyp.
|
||||||
ISrsReader* reader;
|
SrsMp4BoxBrand brand;
|
||||||
|
private:
|
||||||
|
// Underlayer reader and seeker.
|
||||||
|
// @remark The demuxer must use seeker for general MP4 to seek the moov.
|
||||||
|
ISrsReadSeeker* rsio;
|
||||||
// The stream used to demux the boxes.
|
// The stream used to demux the boxes.
|
||||||
// TODO: FIXME: refine for performance issue.
|
// TODO: FIXME: refine for performance issue.
|
||||||
SrsSimpleStream* stream;
|
SrsSimpleStream* stream;
|
||||||
|
@ -1358,13 +1362,15 @@ public:
|
||||||
* @param r The underlayer io reader, user must manage it for decoder never open/free it,
|
* @param r The underlayer io reader, user must manage it for decoder never open/free it,
|
||||||
* the decoder just read data from the reader.
|
* the decoder just read data from the reader.
|
||||||
*/
|
*/
|
||||||
virtual int initialize(ISrsReader* r);
|
virtual int initialize(ISrsReadSeeker* rs);
|
||||||
private:
|
private:
|
||||||
virtual int parse_moov(SrsMp4MovieBox* box);
|
virtual int parse_ftyp(SrsMp4FileTypeBox* ftyp);
|
||||||
|
virtual int parse_moov(SrsMp4MovieBox* moov);
|
||||||
private:
|
private:
|
||||||
// Load the next box from reader.
|
// Load the next box from reader.
|
||||||
// @param required_box_type The box type required, 0 for any box.
|
// @param required_box_type The box type required, 0 for any box.
|
||||||
virtual int load_next_box(SrsMp4Box** ppbox, uint32_t required_box_type);
|
virtual int load_next_box(SrsMp4Box** ppbox, uint32_t required_box_type);
|
||||||
|
// @remark Never load the mdat box content, for it's too large.
|
||||||
virtual int do_load_next_box(SrsMp4Box** ppbox, uint32_t required_box_type);
|
virtual int do_load_next_box(SrsMp4Box** ppbox, uint32_t required_box_type);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1755,7 +1755,7 @@ int64_t srs_flv_tellg(srs_flv_t flv)
|
||||||
void srs_flv_lseek(srs_flv_t flv, int64_t offset)
|
void srs_flv_lseek(srs_flv_t flv, int64_t offset)
|
||||||
{
|
{
|
||||||
FlvContext* context = (FlvContext*)flv;
|
FlvContext* context = (FlvContext*)flv;
|
||||||
context->reader.lseek(offset);
|
context->reader.seek2(offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_bool srs_flv_is_eof(int error_code)
|
srs_bool srs_flv_is_eof(int error_code)
|
||||||
|
|
|
@ -131,7 +131,7 @@ void MockSrsFileReader::skip(int64_t _size)
|
||||||
offset += _size;
|
offset += _size;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t MockSrsFileReader::lseek(int64_t _offset)
|
int64_t MockSrsFileReader::seek2(int64_t _offset)
|
||||||
{
|
{
|
||||||
offset = (int)_offset;
|
offset = (int)_offset;
|
||||||
return offset;
|
return offset;
|
||||||
|
@ -163,6 +163,12 @@ int MockSrsFileReader::read(void* buf, size_t count, ssize_t* pnread)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int MockSrsFileReader::lseek(off_t _offset, int /*whence*/, off_t* /*seeked*/)
|
||||||
|
{
|
||||||
|
offset = (int)_offset;
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
void MockSrsFileReader::mock_append_data(const char* _data, int _size)
|
void MockSrsFileReader::mock_append_data(const char* _data, int _size)
|
||||||
{
|
{
|
||||||
int s = srs_min(MAX_MOCK_DATA_SIZE - offset, _size);
|
int s = srs_min(MAX_MOCK_DATA_SIZE - offset, _size);
|
||||||
|
@ -952,10 +958,10 @@ VOID TEST(KernelFlvTest, FlvVSDecoderSeek)
|
||||||
fs.mock_append_data(tag_header, 11);
|
fs.mock_append_data(tag_header, 11);
|
||||||
EXPECT_TRUE(11 == fs.offset);
|
EXPECT_TRUE(11 == fs.offset);
|
||||||
|
|
||||||
EXPECT_TRUE(ERROR_SUCCESS == dec.lseek(0));
|
EXPECT_TRUE(ERROR_SUCCESS == dec.seek2(0));
|
||||||
EXPECT_TRUE(0 == fs.offset);
|
EXPECT_TRUE(0 == fs.offset);
|
||||||
|
|
||||||
EXPECT_TRUE(ERROR_SUCCESS == dec.lseek(5));
|
EXPECT_TRUE(ERROR_SUCCESS == dec.seek2(5));
|
||||||
EXPECT_TRUE(5 == fs.offset);
|
EXPECT_TRUE(5 == fs.offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -81,10 +81,11 @@ public:
|
||||||
virtual bool is_open();
|
virtual bool is_open();
|
||||||
virtual int64_t tellg();
|
virtual int64_t tellg();
|
||||||
virtual void skip(int64_t size);
|
virtual void skip(int64_t size);
|
||||||
virtual int64_t lseek(int64_t offset);
|
virtual int64_t seek2(int64_t offset);
|
||||||
virtual int64_t filesize();
|
virtual int64_t filesize();
|
||||||
public:
|
public:
|
||||||
virtual int read(void* buf, size_t count, ssize_t* pnread);
|
virtual int read(void* buf, size_t count, ssize_t* pnread);
|
||||||
|
virtual int lseek(off_t offset, int whence, off_t* seeked);
|
||||||
// for mock
|
// for mock
|
||||||
public:
|
public:
|
||||||
// append data to current offset, modify the offset and size.
|
// append data to current offset, modify the offset and size.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue