1
0
Fork 0
mirror of https://github.com/ossrs/srs.git synced 2025-03-09 15:49:59 +00:00

refine flv codec, rename fast encoder to flv vod stream decoder

This commit is contained in:
winlin 2014-07-05 07:40:55 +08:00
parent 032118581a
commit 8271bd657b
4 changed files with 290 additions and 277 deletions

View file

@ -304,7 +304,7 @@ int SrsHttpVhost::response_flv_file2(SrsSocket* skt, SrsHttpMessage* req, string
return ret; return ret;
} }
SrsFlvFastDecoder ffd; SrsFlvVodStreamDecoder ffd;
// open fast decoder // open fast decoder
if ((ret = ffd.initialize(&fs)) != ERROR_SUCCESS) { if ((ret = ffd.initialize(&fs)) != ERROR_SUCCESS) {

View file

@ -225,167 +225,6 @@ int SrsFlvEncoder::write_tag(char* header, int header_size, char* tag, int tag_s
return ret; return ret;
} }
SrsFlvFastDecoder::SrsFlvFastDecoder()
{
_fs = NULL;
tag_stream = new SrsStream();
}
SrsFlvFastDecoder::~SrsFlvFastDecoder()
{
srs_freep(tag_stream);
}
int SrsFlvFastDecoder::initialize(SrsFileReader* fs)
{
int ret = ERROR_SUCCESS;
_fs = fs;
return ret;
}
int SrsFlvFastDecoder::read_header(char** pdata, int* psize)
{
*pdata = NULL;
*psize = 0;
int ret = ERROR_SUCCESS;
srs_assert(_fs);
// 9bytes header and 4bytes first previous-tag-size
int size = 13;
char* buf = new char[size];
if ((ret = _fs->read(buf, size, NULL)) != ERROR_SUCCESS) {
return ret;
}
*pdata = buf;
*psize = size;
return ret;
}
int SrsFlvFastDecoder::read_sequence_header(int64_t* pstart, int* psize)
{
*pstart = 0;
*psize = 0;
int ret = ERROR_SUCCESS;
srs_assert(_fs);
// simply, the first video/audio must be the sequence header.
// and must be a sequence video and audio.
// 11bytes tag header
static char tag_header[] = {
(char)0x00, // TagType UB [5], 9 = video, 8 = audio, 18 = script data
(char)0x00, (char)0x00, (char)0x00, // DataSize UI24 Length of the message.
(char)0x00, (char)0x00, (char)0x00, // Timestamp UI24 Time in milliseconds at which the data in this tag applies.
(char)0x00, // TimestampExtended UI8
(char)0x00, (char)0x00, (char)0x00, // StreamID UI24 Always 0.
};
// discovery the sequence header video and audio.
// @remark, maybe no video or no audio.
bool got_video = false;
bool got_audio = false;
// audio/video sequence and data offset.
int64_t av_sequence_offset_start = -1;
int64_t av_sequence_offset_end = -1;
for (;;) {
if ((ret = _fs->read(tag_header, SRS_FLV_TAG_HEADER_SIZE, NULL)) != ERROR_SUCCESS) {
return ret;
}
if ((ret = tag_stream->initialize(tag_header, SRS_FLV_TAG_HEADER_SIZE)) != ERROR_SUCCESS) {
return ret;
}
int8_t tag_type = tag_stream->read_1bytes();
int32_t data_size = tag_stream->read_3bytes();
bool is_video = tag_type == 0x09;
bool is_audio = tag_type == 0x08;
bool is_not_av = !is_video && !is_audio;
if (is_not_av) {
// skip body and tag size.
_fs->skip(data_size + SRS_FLV_PREVIOUS_TAG_SIZE);
continue;
}
// if video duplicated, no audio
if (is_video && got_video) {
break;
}
// if audio duplicated, no video
if (is_audio && got_audio) {
break;
}
// video
if (is_video) {
srs_assert(!got_video);
got_video = true;
if (av_sequence_offset_start < 0) {
av_sequence_offset_start = _fs->tellg() - SRS_FLV_TAG_HEADER_SIZE;
}
av_sequence_offset_end = _fs->tellg() + data_size + SRS_FLV_PREVIOUS_TAG_SIZE;
_fs->skip(data_size + SRS_FLV_PREVIOUS_TAG_SIZE);
}
// audio
if (is_audio) {
srs_assert(!got_audio);
got_audio = true;
if (av_sequence_offset_start < 0) {
av_sequence_offset_start = _fs->tellg() - SRS_FLV_TAG_HEADER_SIZE;
}
av_sequence_offset_end = _fs->tellg() + data_size + SRS_FLV_PREVIOUS_TAG_SIZE;
_fs->skip(data_size + SRS_FLV_PREVIOUS_TAG_SIZE);
}
}
// seek to the sequence header start offset.
if (av_sequence_offset_start > 0) {
_fs->lseek(av_sequence_offset_start);
*pstart = av_sequence_offset_start;
*psize = (int)(av_sequence_offset_end - av_sequence_offset_start);
}
return ret;
}
int SrsFlvFastDecoder::lseek(int64_t offset)
{
int ret = ERROR_SUCCESS;
srs_assert(_fs);
if (offset >= _fs->filesize()) {
ret = ERROR_SYSTEM_FILE_EOF;
srs_warn("flv fast decoder seek overflow file, "
"size=%"PRId64", offset=%"PRId64", ret=%d",
_fs->filesize(), offset, ret);
return ret;
}
if (_fs->lseek(offset) < 0) {
ret = ERROR_SYSTEM_FILE_SEEK;
srs_warn("flv fast decoder seek error, "
"size=%"PRId64", offset=%"PRId64", ret=%d",
_fs->filesize(), offset, ret);
return ret;
}
return ret;
}
SrsFlvDecoder::SrsFlvDecoder() SrsFlvDecoder::SrsFlvDecoder()
{ {
_fs = NULL; _fs = NULL;
@ -491,3 +330,164 @@ int SrsFlvDecoder::read_previous_tag_size(char ts[4])
return ret; return ret;
} }
SrsFlvVodStreamDecoder::SrsFlvVodStreamDecoder()
{
_fs = NULL;
tag_stream = new SrsStream();
}
SrsFlvVodStreamDecoder::~SrsFlvVodStreamDecoder()
{
srs_freep(tag_stream);
}
int SrsFlvVodStreamDecoder::initialize(SrsFileReader* fs)
{
int ret = ERROR_SUCCESS;
_fs = fs;
return ret;
}
int SrsFlvVodStreamDecoder::read_header(char** pdata, int* psize)
{
*pdata = NULL;
*psize = 0;
int ret = ERROR_SUCCESS;
srs_assert(_fs);
// 9bytes header and 4bytes first previous-tag-size
int size = 13;
char* buf = new char[size];
if ((ret = _fs->read(buf, size, NULL)) != ERROR_SUCCESS) {
return ret;
}
*pdata = buf;
*psize = size;
return ret;
}
int SrsFlvVodStreamDecoder::read_sequence_header(int64_t* pstart, int* psize)
{
*pstart = 0;
*psize = 0;
int ret = ERROR_SUCCESS;
srs_assert(_fs);
// simply, the first video/audio must be the sequence header.
// and must be a sequence video and audio.
// 11bytes tag header
static char tag_header[] = {
(char)0x00, // TagType UB [5], 9 = video, 8 = audio, 18 = script data
(char)0x00, (char)0x00, (char)0x00, // DataSize UI24 Length of the message.
(char)0x00, (char)0x00, (char)0x00, // Timestamp UI24 Time in milliseconds at which the data in this tag applies.
(char)0x00, // TimestampExtended UI8
(char)0x00, (char)0x00, (char)0x00, // StreamID UI24 Always 0.
};
// discovery the sequence header video and audio.
// @remark, maybe no video or no audio.
bool got_video = false;
bool got_audio = false;
// audio/video sequence and data offset.
int64_t av_sequence_offset_start = -1;
int64_t av_sequence_offset_end = -1;
for (;;) {
if ((ret = _fs->read(tag_header, SRS_FLV_TAG_HEADER_SIZE, NULL)) != ERROR_SUCCESS) {
return ret;
}
if ((ret = tag_stream->initialize(tag_header, SRS_FLV_TAG_HEADER_SIZE)) != ERROR_SUCCESS) {
return ret;
}
int8_t tag_type = tag_stream->read_1bytes();
int32_t data_size = tag_stream->read_3bytes();
bool is_video = tag_type == 0x09;
bool is_audio = tag_type == 0x08;
bool is_not_av = !is_video && !is_audio;
if (is_not_av) {
// skip body and tag size.
_fs->skip(data_size + SRS_FLV_PREVIOUS_TAG_SIZE);
continue;
}
// if video duplicated, no audio
if (is_video && got_video) {
break;
}
// if audio duplicated, no video
if (is_audio && got_audio) {
break;
}
// video
if (is_video) {
srs_assert(!got_video);
got_video = true;
if (av_sequence_offset_start < 0) {
av_sequence_offset_start = _fs->tellg() - SRS_FLV_TAG_HEADER_SIZE;
}
av_sequence_offset_end = _fs->tellg() + data_size + SRS_FLV_PREVIOUS_TAG_SIZE;
_fs->skip(data_size + SRS_FLV_PREVIOUS_TAG_SIZE);
}
// audio
if (is_audio) {
srs_assert(!got_audio);
got_audio = true;
if (av_sequence_offset_start < 0) {
av_sequence_offset_start = _fs->tellg() - SRS_FLV_TAG_HEADER_SIZE;
}
av_sequence_offset_end = _fs->tellg() + data_size + SRS_FLV_PREVIOUS_TAG_SIZE;
_fs->skip(data_size + SRS_FLV_PREVIOUS_TAG_SIZE);
}
}
// seek to the sequence header start offset.
if (av_sequence_offset_start > 0) {
_fs->lseek(av_sequence_offset_start);
*pstart = av_sequence_offset_start;
*psize = (int)(av_sequence_offset_end - av_sequence_offset_start);
}
return ret;
}
int SrsFlvVodStreamDecoder::lseek(int64_t offset)
{
int ret = ERROR_SUCCESS;
srs_assert(_fs);
if (offset >= _fs->filesize()) {
ret = ERROR_SYSTEM_FILE_EOF;
srs_warn("flv fast decoder seek overflow file, "
"size=%"PRId64", offset=%"PRId64", ret=%d",
_fs->filesize(), offset, ret);
return ret;
}
if (_fs->lseek(offset) < 0) {
ret = ERROR_SYSTEM_FILE_SEEK;
srs_warn("flv fast decoder seek error, "
"size=%"PRId64", offset=%"PRId64", ret=%d",
_fs->filesize(), offset, ret);
return ret;
}
return ret;
}

View file

@ -49,8 +49,9 @@ public:
virtual ~SrsFlvEncoder(); virtual ~SrsFlvEncoder();
public: public:
/** /**
* initialize the underlayer file stream, * initialize the underlayer file stream.
* user can initialize multiple times to encode multiple flv files. * @remark user can initialize multiple times to encode multiple flv files.
* @remark, user must free the fs, flv encoder never close/free it.
*/ */
virtual int initialize(SrsFileWriter* fs); virtual int initialize(SrsFileWriter* fs);
public: public:
@ -85,21 +86,50 @@ private:
}; };
/** /**
* decode flv fast by only decoding the header and tag. * decode flv file.
*/ */
class SrsFlvFastDecoder class SrsFlvDecoder
{ {
private: private:
SrsFileReader* _fs; SrsFileReader* _fs;
private: private:
SrsStream* tag_stream; SrsStream* tag_stream;
public: public:
SrsFlvFastDecoder(); SrsFlvDecoder();
virtual ~SrsFlvFastDecoder(); virtual ~SrsFlvDecoder();
public: public:
/** /**
* initialize the underlayer file stream, * initialize the underlayer file stream
* user can initialize multiple times to encode multiple flv files. * @remark user can initialize multiple times to decode multiple flv files.
* @remark, user must free the fs, flv decoder never close/free it.
*/
virtual int initialize(SrsFileReader* fs);
public:
virtual int read_header(char header[9]);
virtual int read_tag_header(char* ptype, int32_t* pdata_size, u_int32_t* ptime);
virtual int read_tag_data(char* data, int32_t size);
virtual int read_previous_tag_size(char ts[4]);
};
/**
* decode flv fast by only decoding the header and tag.
* used for vod flv stream to read the header and sequence header,
* then seek to specified offset.
*/
class SrsFlvVodStreamDecoder
{
private:
SrsFileReader* _fs;
private:
SrsStream* tag_stream;
public:
SrsFlvVodStreamDecoder();
virtual ~SrsFlvVodStreamDecoder();
public:
/**
* initialize the underlayer file stream
* @remark user can initialize multiple times to decode multiple flv files.
* @remark, user must free the fs, flv decoder never close/free it.
*/ */
virtual int initialize(SrsFileReader* fs); virtual int initialize(SrsFileReader* fs);
public: public:
@ -118,29 +148,4 @@ public:
virtual int lseek(int64_t offset); virtual int lseek(int64_t offset);
}; };
/**
* decode flv file.
*/
class SrsFlvDecoder
{
private:
SrsFileReader* _fs;
private:
SrsStream* tag_stream;
public:
SrsFlvDecoder();
virtual ~SrsFlvDecoder();
public:
/**
* initialize the underlayer file stream,
* user can initialize multiple times to decode multiple flv files.
*/
virtual int initialize(SrsFileReader* fs);
public:
virtual int read_header(char header[9]);
virtual int read_tag_header(char* ptype, int32_t* pdata_size, u_int32_t* ptime);
virtual int read_tag_data(char* data, int32_t size);
virtual int read_previous_tag_size(char ts[4]);
};
#endif #endif

View file

@ -26,88 +26,7 @@ using namespace std;
#include <srs_kernel_error.hpp> #include <srs_kernel_error.hpp>
#include <srs_kernel_codec.hpp> #include <srs_kernel_codec.hpp>
#include <srs_kernel_flv.hpp>
VOID TEST(KernelCodecTest, IsKeyFrame)
{
int8_t data;
data = 0x10;
EXPECT_TRUE(SrsFlvCodec::video_is_keyframe(&data, 1));
EXPECT_FALSE(SrsFlvCodec::video_is_keyframe(&data, 0));
data = 0x20;
EXPECT_FALSE(SrsFlvCodec::video_is_keyframe(&data, 1));
}
VOID TEST(KernelCodecTest, IsH264)
{
int8_t data;
EXPECT_FALSE(SrsFlvCodec::video_is_h264(&data, 0));
data = 0x17;
EXPECT_TRUE(SrsFlvCodec::video_is_h264(&data, 1));
data = 0x07;
EXPECT_TRUE(SrsFlvCodec::video_is_h264(&data, 1));
data = 0x08;
EXPECT_FALSE(SrsFlvCodec::video_is_h264(&data, 1));
}
VOID TEST(KernelCodecTest, IsSequenceHeader)
{
int16_t data;
char* pp = (char*)&data;
EXPECT_FALSE(SrsFlvCodec::video_is_sequence_header((int8_t*)pp, 0));
EXPECT_FALSE(SrsFlvCodec::video_is_sequence_header((int8_t*)pp, 1));
pp[0] = 0x17;
pp[1] = 0x00;
EXPECT_TRUE(SrsFlvCodec::video_is_sequence_header((int8_t*)pp, 2));
pp[0] = 0x18;
EXPECT_FALSE(SrsFlvCodec::video_is_sequence_header((int8_t*)pp, 2));
pp[0] = 0x27;
EXPECT_FALSE(SrsFlvCodec::video_is_sequence_header((int8_t*)pp, 2));
pp[0] = 0x17;
pp[1] = 0x01;
EXPECT_FALSE(SrsFlvCodec::video_is_sequence_header((int8_t*)pp, 2));
}
VOID TEST(KernelCodecTest, IsAAC)
{
int8_t data;
EXPECT_FALSE(SrsFlvCodec::audio_is_aac(&data, 0));
data = 0xa0;
EXPECT_TRUE(SrsFlvCodec::audio_is_aac(&data, 1));
data = 0xa7;
EXPECT_TRUE(SrsFlvCodec::audio_is_aac(&data, 1));
data = 0x00;
EXPECT_FALSE(SrsFlvCodec::audio_is_aac(&data, 1));
}
VOID TEST(KernelCodecTest, IsAudioSequenceHeader)
{
int16_t data;
char* pp = (char*)&data;
EXPECT_FALSE(SrsFlvCodec::audio_is_sequence_header((int8_t*)pp, 0));
EXPECT_FALSE(SrsFlvCodec::audio_is_sequence_header((int8_t*)pp, 1));
pp[0] = 0xa0;
pp[1] = 0x00;
EXPECT_TRUE(SrsFlvCodec::audio_is_sequence_header((int8_t*)pp, 2));
pp[0] = 0x00;
EXPECT_FALSE(SrsFlvCodec::video_is_sequence_header((int8_t*)pp, 2));
pp[0] = 0xa0;
pp[1] = 0x01;
EXPECT_FALSE(SrsFlvCodec::video_is_sequence_header((int8_t*)pp, 2));
}
MockSrsFileWriter::MockSrsFileWriter() MockSrsFileWriter::MockSrsFileWriter()
{ {
@ -194,3 +113,92 @@ int MockSrsFileReader::read(void* buf, size_t count, ssize_t* pnread)
int ret = ERROR_SUCCESS; int ret = ERROR_SUCCESS;
return ret; return ret;
} }
VOID TEST(KernelCodecTest, IsKeyFrame)
{
int8_t data;
data = 0x10;
EXPECT_TRUE(SrsFlvCodec::video_is_keyframe(&data, 1));
EXPECT_FALSE(SrsFlvCodec::video_is_keyframe(&data, 0));
data = 0x20;
EXPECT_FALSE(SrsFlvCodec::video_is_keyframe(&data, 1));
}
VOID TEST(KernelCodecTest, IsH264)
{
int8_t data;
EXPECT_FALSE(SrsFlvCodec::video_is_h264(&data, 0));
data = 0x17;
EXPECT_TRUE(SrsFlvCodec::video_is_h264(&data, 1));
data = 0x07;
EXPECT_TRUE(SrsFlvCodec::video_is_h264(&data, 1));
data = 0x08;
EXPECT_FALSE(SrsFlvCodec::video_is_h264(&data, 1));
}
VOID TEST(KernelCodecTest, IsSequenceHeader)
{
int16_t data;
char* pp = (char*)&data;
EXPECT_FALSE(SrsFlvCodec::video_is_sequence_header((int8_t*)pp, 0));
EXPECT_FALSE(SrsFlvCodec::video_is_sequence_header((int8_t*)pp, 1));
pp[0] = 0x17;
pp[1] = 0x00;
EXPECT_TRUE(SrsFlvCodec::video_is_sequence_header((int8_t*)pp, 2));
pp[0] = 0x18;
EXPECT_FALSE(SrsFlvCodec::video_is_sequence_header((int8_t*)pp, 2));
pp[0] = 0x27;
EXPECT_FALSE(SrsFlvCodec::video_is_sequence_header((int8_t*)pp, 2));
pp[0] = 0x17;
pp[1] = 0x01;
EXPECT_FALSE(SrsFlvCodec::video_is_sequence_header((int8_t*)pp, 2));
}
VOID TEST(KernelCodecTest, IsAAC)
{
int8_t data;
EXPECT_FALSE(SrsFlvCodec::audio_is_aac(&data, 0));
data = 0xa0;
EXPECT_TRUE(SrsFlvCodec::audio_is_aac(&data, 1));
data = 0xa7;
EXPECT_TRUE(SrsFlvCodec::audio_is_aac(&data, 1));
data = 0x00;
EXPECT_FALSE(SrsFlvCodec::audio_is_aac(&data, 1));
}
VOID TEST(KernelCodecTest, IsAudioSequenceHeader)
{
int16_t data;
char* pp = (char*)&data;
EXPECT_FALSE(SrsFlvCodec::audio_is_sequence_header((int8_t*)pp, 0));
EXPECT_FALSE(SrsFlvCodec::audio_is_sequence_header((int8_t*)pp, 1));
pp[0] = 0xa0;
pp[1] = 0x00;
EXPECT_TRUE(SrsFlvCodec::audio_is_sequence_header((int8_t*)pp, 2));
pp[0] = 0x00;
EXPECT_FALSE(SrsFlvCodec::video_is_sequence_header((int8_t*)pp, 2));
pp[0] = 0xa0;
pp[1] = 0x01;
EXPECT_FALSE(SrsFlvCodec::video_is_sequence_header((int8_t*)pp, 2));
}
VOID TEST(KernelFlvTest, IsAudioSequenceHeader)
{
MockSrsFileWriter fs;
SrsFlvEncoder enc;
ASSERT_TRUE(ERROR_SUCCESS == enc.initialize(&fs));
}