mpeg-4(mpeg4和h265有区别么)

前沿拓展:

mpeg-4

这个文件本身能被所有的视频拼接软件支持。
建议先把它转换为AVI、MPEG等其中的一种格式再拼接,拼接用系统自带的MOVIE MAKER或者ultra video converter都可以。


0.引言

阅读本文前,可以先阅读前面的文章,能够帮助你更好理解本篇文章。文章列表如下:

SRS流媒体服务器之HLS源码分析(3)

SRS流媒体服务器之HLS源码分析(1)

SRS流媒体服务器之HLS源码分析(2)

SRS流媒体服务器之HLS配置、测试和技术选型

SRS流媒体服务器集群之Edge模式(3)

SRS流媒体服务器集群之Edge模式(2)

SRS流媒体服务器集群之Edge模式(1)

SRS流媒体服务器集群之Forward模式(2)

SRS流媒体服务器集群之Forward模式(1)

SRS流媒体服务器之HTTP-FLV框架分析(1)

SRS流媒体服务器之RTMP推流消息处理(1)

SRS流媒体服务器之RTMP协议分析(2)

SRS流媒体框架分析(1)

SRS流媒体之RTMP推流框架分析(2)

SRS流媒体之RTMP拉流框架分析(3)

SRS流媒体服务器之RTMP协议分析(1)

简述SRS流媒体服务器相关技术

流媒体推拉流实战之RTMP协议分析(BAT面试官推荐)

流媒体服务器架构与应用分析

手把手搭建流媒体服务器详细步骤

手把手搭建FFmpeg的Windows环境

超详细手把手搭建在ubuntu系统的FFmpeg环境

本篇文章主要讲解拉流时,重点讲解读取hls数据的流程。

1.读取ts和m3u8文件源码分析

(1)启动gdb调试

gdb ./objs/srs

set args -c conf/srs.conf

b main

c

如下界面:

mpeg-4(mpeg4和h265有区别么)

(2)先保证能够成功推流,然后运行成功。查看m3u8和ts文件的生成。如下界面:

mpeg-4(mpeg4和h265有区别么)

(3)这个时候再启动拉流,看看SRS流媒体服务端的打印,可以看到客户端请求m3u8和ts文件,首先请求m3u8文件,再找到m3u8文件的路径和对应的处理,SRS流媒体服务器,把这个m3u8文件发送给客户端,客户端收到m3u8文件,就会解析对应的ts文件,客户端请求ts文件,是按照顺序请求。如下界面:

mpeg-4(mpeg4和h265有区别么)

注意:HLS的延迟,不仅仅只是一个fragment的延迟,这个延迟时间由分片的总数量来决定。为了降低延时,尽量减少分片的总数量,但是也要保证至少有2个分片,在配置文件中,也就是减少hls_window的值,如下图:

mpeg-4(mpeg4和h265有区别么)

(4)拉流时,使用SrsFileReader去读取m3u8文件,打印断点,输入如下命令:

b SrsFileReader::SrsFileReader

查看函数调用栈,如下调用顺序(从13到0)。

/**
* file reader, to read from file.
*/
class SrsFileReader : public ISrsReadSeeker
{
private:
std::string path;
int fd;
public:
SrsFileReader();
virtual ~SrsFileReader();
public:
/**
* open file reader.
* @param p a string indicates the path of file to open.
*/
virtual srs_error_t open(std::string p);
/**
* close current reader.
* @remark user can reopen again.
*/
virtual void close();
public:
// TODO: FIXME: extract interface.
virtual bool is_open();
virtual int64_t tellg();
virtual void skip(int64_t size);
virtual int64_t seek2(int64_t offset);
virtual int64_t filesize();
// Interface ISrsReadSeeker
public:
virtual srs_error_t read(void* buf, size_t count, ssize_t* pnread);
virtual srs_error_t lseek(off_t offset, int whence, off_t* seeked);
};

// For utest to mock it.
typedef int (*_srs_open_t)(const char* path, int oflag, …);
typedef ssize_t (*_srs_write_t)(int fildes, const void* buf, size_t nbyte);
typedef ssize_t (*_srs_read_t)(int fildes, void* buf, size_t nbyte);
typedef off_t (*_srs_lseek_t)(int fildes, off_t offset, int whence);
typedef int (*_srs_close_t)(int fildes);

#endif

(5)拉流时,使用SrsFileReader去读取ts文件,打印断点,输入如下命令:

b SrsFileReader::SrsFileReader

查看函数调用栈,如下调用顺序(从11到0)。

/**
* file reader, to read from file.
*/
class SrsFileReader : public ISrsReadSeeker
{
private:
std::string path;
int fd;
public:
SrsFileReader();
virtual ~SrsFileReader();
public:
/**
* open file reader.
* @param p a string indicates the path of file to open.
*/
virtual srs_error_t open(std::string p);
/**
* close current reader.
* @remark user can reopen again.
*/
virtual void close();
public:
// TODO: FIXME: extract interface.
virtual bool is_open();
virtual int64_t tellg();
virtual void skip(int64_t size);
virtual int64_t seek2(int64_t offset);
virtual int64_t filesize();
// Interface ISrsReadSeeker
public:
virtual srs_error_t read(void* buf, size_t count, ssize_t* pnread);
virtual srs_error_t lseek(off_t offset, int whence, off_t* seeked);
};

// For utest to mock it.
typedef int (*_srs_open_t)(const char* path, int oflag, …);
typedef ssize_t (*_srs_write_t)(int fildes, const void* buf, size_t nbyte);
typedef ssize_t (*_srs_read_t)(int fildes, void* buf, size_t nbyte);
typedef off_t (*_srs_lseek_t)(int fildes, off_t offset, int whence);
typedef int (*_srs_close_t)(int fildes);

#endif

接下来整个源码分析,都是围绕读取ts和m3u8文件去展开。

(6)拉流时,一定会使用这个类,SrsFileReader,源码如下:

/**
* file reader, to read from file.
*/
class SrsFileReader : public ISrsReadSeeker
{
private:
std::string path;
int fd;
public:
SrsFileReader();
virtual ~SrsFileReader();
public:
/**
* open file reader.
* @param p a string indicates the path of file to open.
*/
virtual srs_error_t open(std::string p);
/**
* close current reader.
* @remark user can reopen again.
*/
virtual void close();
public:
// TODO: FIXME: extract interface.
virtual bool is_open();
virtual int64_t tellg();
virtual void skip(int64_t size);
virtual int64_t seek2(int64_t offset);
virtual int64_t filesize();
// Interface ISrsReadSeeker
public:
virtual srs_error_t read(void* buf, size_t count, ssize_t* pnread);
virtual srs_error_t lseek(off_t offset, int whence, off_t* seeked);
};

// For utest to mock it.
typedef int (*_srs_open_t)(const char* path, int oflag, …);
typedef ssize_t (*_srs_write_t)(int fildes, const void* buf, size_t nbyte);
typedef ssize_t (*_srs_read_t)(int fildes, void* buf, size_t nbyte);
typedef off_t (*_srs_lseek_t)(int fildes, off_t offset, int whence);
typedef int (*_srs_close_t)(int fildes);

#endif

(7)在 SrsFileReader里,打开文件函数,打印断点:

b SrsFileReader::open(string p)

c

如下界面:

mpeg-4(mpeg4和h265有区别么)

拉流时,读取ts文件,查看调用栈。如下界面:

mpeg-4(mpeg4和h265有区别么)

函数调用关系(编号从12到0)如下。

1 SrsFileReader::open at src/kernel/srs_kernel_file.cpp:207

2 SrsHttpFileServer::serve_file at src/protocol/srs_http_stack.cpp:394

3 SrsHttpFileServer::serve_http at src/protocol/srs_http_stack.cpp:384

4 SrsHttpServerMux::server_http at src/protocol/srs_http_stack.cpp:711

5 SrsHttpServer::serve_http src/app/srs_app_http_conn.cpp:303

6 SrsHttpCorsMux::server_http at src/app/srs_http_stack.cpp:859

7 SrsHttpConn::process_request at src/app/srs_app_http_conn.cpp:161

8 SrsHttpConn::do_cycle at src/app/srs_app_http_conn.cpp:133

9 0x00000000004d10fb in SrsConnection::cycle (this=0xa76ea0) at src/app/srs_app_conn.cpp:171

10 0x0000000000509c88 in SrsSTCoroutine::cycle (this=0xa5aa20) at src/app/srs_app_st.cpp:198

11 0x0000000000509cfd in SrsSTCoroutine::pfn (arg=0xa5aa20) at src/app/srs_app_st.cpp:213
—Type <return> to continue, or q <return> to quit—

12 0x00000000005bdd9d in _st_thread_main () at sched.c:337

13 0x00000000005be515 in st_thread_create (start=0x5bd719 <_st_vp_schedule+170>, arg=0x900000001,
joinable=1, stk_size=1) at sched.c:616

(8)这里要区分http-flv动态文件,还是hls。

srs_error_t SrsHttpServer::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
{
srs_error_t err = srs_success;

// try http stream first.
ISrsHttpHandler* h = NULL;
if ((err = http_stream->mux.find_handler(r, &h)) != srs_success) {
return srs_error_wrap(err, "find handler");
}
if (!h->is_not_found()) {
return http_stream->mux.serve_http(w, r);//http-flv,这里调用的mux作用是不一样
}

return http_static->mux.serve_http(w, r);//hls,http-flv,这里调用的mux作用是不一样
}

(9)根据这个handle函数调用,传递不同的url,进而使用不同处理函数。源码如下:

srs_error_t SrsHttpServeMux::handle(std::string pattern, ISrsHttpHandler* handler)
{
srs_assert(handler);

if (pattern.empty()) {
return srs_error_new(ERROR_HTTP_PATTERN_EMPTY, "empty pattern");
}

if (entries.find(pattern) != entries.end()) {
SrsHttpMuxEntry* exists = entries[pattern];
if (exists->explicit_match) {
return srs_error_new(ERROR_HTTP_PATTERN_DUPLICATED, "pattern=%s exists", pattern.c_str());
}
}

std::string vhost = pattern;
if (pattern.at(0) != '/') {
if (pattern.find("/") != string::npos) {
vhost = pattern.substr(0, pattern.find("/"));
}
vhosts[vhost] = handler;
}

if (true) {
SrsHttpMuxEntry* entry = new SrsHttpMuxEntry();//创建路由,可以分出不同的server
entry->explicit_match = true;
entry->handler = handler; //具体由哪个handler(不同server)处理
entry->pattern = pattern;//对应的url
entry->handler->entry = entry;

if (entries.find(pattern) != entries.end()) {
SrsHttpMuxEntry* exists = entries[pattern];
srs_freep(exists);
}
entries[pattern] = entry;
}

// Helpful behavior:
// If pattern is /tree/, insert an implicit permanent redirect for /tree.
// It can be overridden by an explicit registration.
if (pattern != "/" && !pattern.empty() && pattern.at(pattern.length() – 1) == '/') {
std::string rpattern = pattern.substr(0, pattern.length() – 1);
SrsHttpMuxEntry* entry = NULL;

// free the exists implicit entry
if (entries.find(rpattern) != entries.end()) {
entry = entries[rpattern];
}

// create implicit redirect.
if (!entry || !entry->explicit_match) {
srs_freep(entry);

entry = new SrsHttpMuxEntry();
entry->explicit_match = false;
entry->handler = new SrsHttpRedirectHandler(pattern, SRS_CONSTS_HTTP_Found);
entry->pattern = pattern;
entry->handler->entry = entry;

entries[rpattern] = entry;
}
}

return srs_success;
}

(10)调用匹配函数,源码如下:

srs_error_t SrsHttpServeMux::match(ISrsHttpMessage* r, ISrsHttpHandler** ph)
{
std::string path = r->path();

// Host-specific pattern takes precedence over generic ones
if (!vhosts.empty() && vhosts.find(r->host()) != vhosts.end()) {
path = r->host() + path;
}

int nb_matched = 0;
ISrsHttpHandler* h = NULL;

std::map<std::string, SrsHttpMuxEntry*>::iterator it;
for (it = entries.begin(); it != entries.end(); ++it) {
std::string pattern = it->first;
SrsHttpMuxEntry* entry = it->second;

if (!entry->enabled) {
continue;
}
//调用真实的匹配规则
if (!path_match(pattern, path)) {
continue;
}
//匹配完之后,就是为了找到对应的handler
if (!h || (int)pattern.length() > nb_matched) {
nb_matched = (int)pattern.length();
h = entry->handler;
}
}

*ph = h;

return srs_success;
}

(11)具体匹配规则是调用如下这个函数,源码如下:

bool SrsHttpServeMux::path_match(string pattern, string path)
{
if (pattern.empty()) {
return false;
}

int n = (int)pattern.length();

// not endswith '/', exactly match.
//精确匹配
if (pattern.at(n – 1) != '/') {
return pattern == path;
}

// endswith '/', match any,
// for example, '/api/' match '/api/[N]'
//只需要根据前缀匹配,就是path的前部分和pattern匹配就行,如/live/livestream.m3u8和/匹配
if ((int)path.length() >= n) {
if (memcmp(pattern.data(), path.data(), n) == 0) {
return true;
}
}

return false;
}

源码如下:

srs_error_t SrsHttpServeMux::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
{
srs_error_t err = srs_success;

ISrsHttpHandler* h = NULL;
if ((err = find_handler(r, &h)) != srs_success) {
return srs_error_wrap(err, "find handler");
}

srs_assert(h);
//当为hls的时候,这个server就是SrsHttpFileServer
if ((err = h->serve_http(w, r)) != srs_success) {
return srs_error_wrap(err, "serve http");
}

return err;
}

(12)注册这个url,所对应的handler。

srs_error_t SrsHttpServer::initialize()
{
srs_error_t err = srs_success;

// for SRS go-sharp to detect the status of HTTP server of SRS HTTP FLV Cluster.
//这里的路径"/api/v1/versions"不是以斜线结束,就是使用精确匹配
if ((err = http_static->mux.handle("/api/v1/versions", new SrsGoApiVersion())) != srs_success) {
return srs_error_wrap(err, "handle versin");
}
//直播流,如http-flv
if ((err = http_stream->initialize()) != srs_success) {
return srs_error_wrap(err, "http stream");
}
//静态文件 如hls
if ((err = http_static->initialize()) != srs_success) {
return srs_error_wrap(err, "http static");
}

return err;
}

这个SrsHttpFileServer也是继承ISrsHttpHandler,源码如下:

srs_error_t SrsHttpResponseWriter::final_request()
{
srs_error_t err = srs_success;

// write the header data in memory.
if (!header_wrote) {
write_header(SRS_CONSTS_HTTP_OK);
}

// whatever header is wrote, we should try to send header.
if ((err = send_header(NULL, 0)) != srs_success) {
return srs_error_wrap(err, "send header");
}

// complete the chunked encoding.
if (content_length == -1) {
std::stringstream ss;
ss << 0 << SRS_HTTP_CRLF << SRS_HTTP_CRLF;
std::string ch = ss.str();
return skt->write((void*)ch.data(), (int)ch.length(), NULL);
}

// flush when send with content length
return write(NULL, 0);
}

(13)查找文件是否存在,如果有就保存,没有就要创建,然后再保存。源码如下:

srs_error_t SrsHttpResponseWriter::final_request()
{
srs_error_t err = srs_success;

// write the header data in memory.
if (!header_wrote) {
write_header(SRS_CONSTS_HTTP_OK);
}

// whatever header is wrote, we should try to send header.
if ((err = send_header(NULL, 0)) != srs_success) {
return srs_error_wrap(err, "send header");
}

// complete the chunked encoding.
if (content_length == -1) {
std::stringstream ss;
ss << 0 << SRS_HTTP_CRLF << SRS_HTTP_CRLF;
std::string ch = ss.str();
return skt->write((void*)ch.data(), (int)ch.length(), NULL);
}

// flush when send with content length
return write(NULL, 0);
}

(14)创建一个file_reader,读取文件m3u8。

srs_error_t SrsHttpResponseWriter::final_request()
{
srs_error_t err = srs_success;

// write the header data in memory.
if (!header_wrote) {
write_header(SRS_CONSTS_HTTP_OK);
}

// whatever header is wrote, we should try to send header.
if ((err = send_header(NULL, 0)) != srs_success) {
return srs_error_wrap(err, "send header");
}

// complete the chunked encoding.
if (content_length == -1) {
std::stringstream ss;
ss << 0 << SRS_HTTP_CRLF << SRS_HTTP_CRLF;
std::string ch = ss.str();
return skt->write((void*)ch.data(), (int)ch.length(), NULL);
}

// flush when send with content length
return write(NULL, 0);
}

(15)函数SrsHttpFileServer::serve_file调用copy(w, fs, r, (int)left),从文件中读取数据,发送给客户端。

srs_error_t SrsHttpFileServer::copy(ISrsHttpResponseWriter* w, SrsFileReader* fs, ISrsHttpMessage* r, int size)
{
srs_error_t err = srs_success;

int left = size;
char* buf = new char[SRS_HTTP_TS_SEND_BUFFER_SIZE];
SrsAutoFreeA(char, buf);

while (left > 0) {
ssize_t nread = -1;
int max_read = srs_min(left, SRS_HTTP_TS_SEND_BUFFER_SIZE);
if ((err = fs->read(buf, max_read, &nread)) != srs_success) {//从文件中读取数据
return srs_error_wrap(err, "read limit=%d, left=%d", max_read, left);
}

left -= nread;
if ((err = w->write(buf, (int)nread)) != srs_success) {//发送给客户端
return srs_error_wrap(err, "write limit=%d, bytes=%d, left=%d", max_read, nread, left);
}
}

return err;
}

(16)结束客户端请求,源码如下:

srs_error_t SrsHttpResponseWriter::final_request()
{
srs_error_t err = srs_success;

// write the header data in memory.
if (!header_wrote) {
write_header(SRS_CONSTS_HTTP_OK);
}

// whatever header is wrote, we should try to send header.
if ((err = send_header(NULL, 0)) != srs_success) {
return srs_error_wrap(err, "send header");
}

// complete the chunked encoding.
if (content_length == -1) {
std::stringstream ss;
ss << 0 << SRS_HTTP_CRLF << SRS_HTTP_CRLF;
std::string ch = ss.str();
return skt->write((void*)ch.data(), (int)ch.length(), NULL);
}

// flush when send with content length
return write(NULL, 0);
}

(17)观察几个重要函数,打印断点:

b SrsHttpFileServer::SrsHttpFileServer()

b SrsHttpMuxEntry::SrsHttpMuxEntry()

b SrsHttpServerMux::SrsHttpServerMux()

b SrsHttpServerMux::handle()

r

界面如下:

mpeg-4(mpeg4和h265有区别么)

运行到断点SrsHttpServerMux::SrsHttpServerMux(),函数调用栈界面如下:

mpeg-4(mpeg4和h265有区别么)

mpeg-4(mpeg4和h265有区别么)

从这里的函数调用栈看出,SrsHttpStreamServer调用的http-live,SrsHttpStaticServer调用的hls,都是通过的路由规则得到的函数。

(18)断点运行到断点SrsHttpMuxEntry::SrsHttpMuxEntry(),函数调用栈运行界面如下:

mpeg-4(mpeg4和h265有区别么)

(19)运行到断点SrsHttpFileServer::SrsHttpFileServer(),函数调用栈如下界面,如下:

mpeg-4(mpeg4和h265有区别么)

(20)在SrsHttpStaticServer初始化的时候,就会注册这个SrsHttpFileServer服务,源码如下:

srs_error_t SrsHttpStaticServer::initialize()
{
srs_error_t err = srs_success;

bool default_root_exists = false;

// http static file and flv vod stream mount for each vhost.
SrsConfDirective* root = _srs_config->get_root();
for (int i = 0; i < (int)root->directives.size(); i++) {
SrsConfDirective* conf = root->at(i);

if (!conf->is_vhost()) {
continue;
}

string pmount;
string vhost = conf->arg0();
if ((err = mount_vhost(vhost, pmount)) != srs_success) {
return srs_error_wrap(err, "mount vhost");
}

if (pmount == "/") {
default_root_exists = true;
std::string dir = _srs_config->get_vhost_http_dir(vhost);
srs_warn("http: root mount to %s", dir.c_str());
}
}

if (!default_root_exists) {
// add root
std::string dir = _srs_config->get_http_stream_dir();
if ((err = mux.handle("/", new SrsVodStream(dir))) != srs_success) {
return srs_error_wrap(err, "mount root dir=%s", dir.c_str());
}
srs_trace("http: root mount to %s", dir.c_str());
}

return err;
}

运行到断点SrsHttpServerMux::handle,使用的是局部匹配,函数调用栈如下:

mpeg-4(mpeg4和h265有区别么)

(21)根据路径url,匹配不同的handle。源码如下:

srs_error_t SrsServer::http_handle()
{
srs_error_t err = srs_success;

if ((err = http_api_mux->handle("/", new SrsHttpNotFoundHandler())) != srs_success) {
return srs_error_wrap(err, "handle not found");
}
if ((err = http_api_mux->handle("/api/", new SrsGoApiApi())) != srs_success) {
return srs_error_wrap(err, "handle api");
}
if ((err = http_api_mux->handle("/api/v1/", new SrsGoApiV1())) != srs_success) {
return srs_error_wrap(err, "handle v1");
}
if ((err = http_api_mux->handle("/api/v1/versions", new SrsGoApiVersion())) != srs_success) {
return srs_error_wrap(err, "handle versions");
}
if ((err = http_api_mux->handle("/api/v1/summaries", new SrsGoApiSummaries())) != srs_success) {
return srs_error_wrap(err, "handle summaries");
}
if ((err = http_api_mux->handle("/api/v1/rusages", new SrsGoApiRusages())) != srs_success) {
return srs_error_wrap(err, "handle rusages");
}
if ((err = http_api_mux->handle("/api/v1/self_proc_stats", new SrsGoApiSelfProcStats())) != srs_success) {
return srs_error_wrap(err, "handle self proc stats");
}
if ((err = http_api_mux->handle("/api/v1/system_proc_stats", new SrsGoApiSystemProcStats())) != srs_success) {
return srs_error_wrap(err, "handle system proc stats");
}
if ((err = http_api_mux->handle("/api/v1/meminfos", new SrsGoApiMemInfos())) != srs_success) {
return srs_error_wrap(err, "handle meminfos");
}
if ((err = http_api_mux->handle("/api/v1/authors", new SrsGoApiAuthors())) != srs_success) {
return srs_error_wrap(err, "handle authors");
}
if ((err = http_api_mux->handle("/api/v1/features", new SrsGoApiFeatures())) != srs_success) {
return srs_error_wrap(err, "handle features");
}
if ((err = http_api_mux->handle("/api/v1/vhosts/", new SrsGoApiVhosts())) != srs_success) {
return srs_error_wrap(err, "handle vhosts");
}
if ((err = http_api_mux->handle("/api/v1/streams/", new SrsGoApiStreams())) != srs_success) {
return srs_error_wrap(err, "handle streams");
}
if ((err = http_api_mux->handle("/api/v1/clients/", new SrsGoApiClients())) != srs_success) {
return srs_error_wrap(err, "handle clients");
}
if ((err = http_api_mux->handle("/api/v1/raw", new SrsGoApiRaw(this))) != srs_success) {
return srs_error_wrap(err, "handle raw");
}
if ((err = http_api_mux->handle("/api/v1/clusters", new SrsGoApiClusters())) != srs_success) {
return srs_error_wrap(err, "handle raw");
}

// test the request info.
if ((err = http_api_mux->handle("/api/v1/tests/requests", new SrsGoApiRequests())) != srs_success) {
return srs_error_wrap(err, "handle tests requests");
}
// test the error code response.
if ((err = http_api_mux->handle("/api/v1/tests/errors", new SrsGoApiError())) != srs_success) {
return srs_error_wrap(err, "handle tests errors");
}
// test the redirect mechenism.
if ((err = http_api_mux->handle("/api/v1/tests/redirects", new SrsHttpRedirectHandler("/api/v1/tests/errors", SRS_CONSTS_HTTP_MovedPermanently))) != srs_success) {
return srs_error_wrap(err, "handle tests redirects");
}
// test the http vhost.
if ((err = http_api_mux->handle("error.srs.com/api/v1/tests/errors", new SrsGoApiError())) != srs_success) {
return srs_error_wrap(err, "handle tests errors for error.srs.com");
}

// TODO: FIXME: for console.
// TODO: FIXME: support reload.
std::string dir = _srs_config->get_http_stream_dir() + "/console";
if ((err = http_api_mux->handle("/console/", new SrsHttpFileServer(dir))) != srs_success) {
return srs_error_wrap(err, "handle console at %s", dir.c_str());
}
srs_trace("http: api mount /console to %s", dir.c_str());

return err;
}

(22)下面通过断点来看看,http-flv和hls的区别,输入命令:

b srs_app_http_conn.cpp:296

b srs_app_http_conn.cpp:303

c

界面如下:

mpeg-4(mpeg4和h265有区别么)

可以通过调试发现,就会运行到http_stream->mux.serve_http(w,r)。

mpeg-4(mpeg4和h265有区别么)

就像前面源码分析的一样,会调用match函数去匹配。调试界面如下:

mpeg-4(mpeg4和h265有区别么)

逐一运行,然后找到handler。调试界面如下:

mpeg-4(mpeg4和h265有区别么)

mpeg-4(mpeg4和h265有区别么)

(23)继续打印断点,输入如下命令:

b srs_http_stack.cpp:737

c

如下界面:

mpeg-4(mpeg4和h265有区别么)

注意:上面已经有了很多断点,也可以取消,使用disable 断点号。

2.总结

本文重点讲解了,拉流hls时的流程,先发起http请求,然后SRS流媒体服务器发个m3u8文件,客户端根据m3u8文件,去请求ts文件,一直循环读取ts码流。更细节的分析,需要根据函数调用栈去阅读源码,上面已经给出详细的分析,如果想要拓展或其它分析,可以根据本篇文章提供的方法,去研究。欢迎关注,转发,点赞,收藏,分享,评论区讨论。

后期关于项目的知识,会在微信公众号上更新,如果想要学习项目,可以关注微信公众号“记录世界 from antonio”

mpeg-4(mpeg4和h265有区别么)

拓展知识:

mpeg-4

究竟什么是MP4呢?就像人们把MP3随身听简称为MP3 一样,MP4便携式视频播放器也同样被简称为MP4。当然,也就像MP3并不是MPEG3那样,MP4也不是MPEG4,它们所采用的名称与自身的底层技术应用没有直接关系,MP4的概念实际上已被厂商延伸。

MP4概念无外乎有两种概念,一种是指继MP3之后的音乐格式,从技术层面讲,MP4使用MPEG-2 AAC技术,也就是简称为A2B或AAC的技术。它的特点是音质更加完美而压缩比更大(15:1-20:1)。它增加了诸如对立体声的完美再现、比特流效果音扫描、多媒体控制、降噪等MP3没有的特性,使得在音频压缩后仍能完美的再现CD的音质。

另外一种是指支持MPEG-4这种视频格式的便携式播放器,我们先来看看什么是MP4。MP4(也叫MPEG-4)是MPEG格式的一种,是活动图像的一种压缩方式。通过这种压缩,可以使用较小的文件提供较高的图像质量,是目前最流行(尤其在网络中)的视频文件格式之一。这种格式的好处是它不仅可覆盖低频带,也向高频带发展。MP4从其提出之日起就引起了人们的广泛关注,目前MP4最流行使用的压缩方式为DivX和XviD。经过以DivX或者XviD为代表的MP4技术处理过的DVD节目,图像的视频、音频质量下降不大,但体积却缩小到原来的几分之一,可以很方便地用两张650MB容量的普通CD-ROM来保存生成的文件。用一张盘就可以容纳一百零几分钟的一部电影,而此时的画面质量明显优于VCD。

MP4,硬要说的话,它只是一种压缩标准,就好象VCD 是基于MP2的,

MP3好象只能压缩音频,MP4音频、视频都可以压缩的,平时电脑上有些

需要安装什么插件(DIVX、FFDSHOW)之类的才能看的电影,

就是用MP4压缩的。

参考资料:
http://zhidao.baidu.com/question/1966384.html?si=1

本回答被提问者采纳

mpeg-4

不一样,MP4是一种格式,mpeg4是一种编码,mpeg4是目前最清晰的一种视频编码,现在一些最清晰的格式比如MKV.avi.mov等MP4的格式如果能达到1080P也属于MPEG4,目前手机网上的视频也在720p左右属于MPEG2低于480P属于mpeg1,只不过MP4格式名称而已和mpg4无关

mpeg-4

MP4可以理解为
可以播放视频的便携式播放器。。
MPEG-4
是一种视频的编码方式,这个你可以理解为:各种格式的视频就像不同的字体,只是写法不一样,不同的编码速度不一样,电脑的支持也不一样。
够通俗了吧。。

mpeg-4

楼下的说的不怎么对……mp4是一种打包格式,就是指后面几个字母,而mpeg4是一种类似内核的东东,就是里面装的东东……比如你去买菜,篮子叫mp4,菜叫mpeg4………好吧,这个比喻很恰当……

原创文章,作者:趣淘网小编,如若转载,请注明出处:http://www.3322388.com/75734.html

发表评论

邮箱地址不会被公开。 必填项已用*标注