永发信息网

ffmpeg分析 之 如何解析mpegts流

答案:2  悬赏:10  手机版
解决时间 2021-03-04 19:29
  • 提问者网友:骑士
  • 2021-03-03 22:53
ffmpeg分析 之 如何解析mpegts流
最佳答案
  • 五星知识达人网友:天凉才是好个秋
  • 2021-03-04 00:25
AVInputFormat mpegts_demuxer = { "mpegts", NULL_IF_CONFIG_SMALL("MPEG-2 transport stream format"), sizeof(MpegTSContext), mpegts_probe, mpegts_read_header, mpegts_read_packet, mpegts_read_close, read_seek, mpegts_get_pcr, .flags = AVFMT_SHOW_IDS|AVFMT_TS_DISCONT,};mpegts_probe:这函数一看就知道是检测数据格式是不是mpegts格式的。
mpegts_read_header:读数据头信息,比如在ts流当中的数据包大小,还ts流中的节目信息,sdt表,pmt表,video pid,audio pid等等,以便后面读数据时使用。
pos = url_ftell(pb);len = get_buffer(pb, buf, sizeof(buf));if (len != sizeof(buf)) goto fail;ts->raw_packet_size = get_packet_size(buf, sizeof(buf));if (ts->raw_packet_size <= 0) goto fail; 上面这几行代码是从数据流当中读了5 * 1024个字节来判断数据包的大小raw_packet_size,一般这个值是188,当然如果这个ts流不是标准和dvb ts流的话,那当然会不一样的。
url_fseek(pb, pos, SEEK_SET);mpegts_scan_sdt(ts);mpegts_set_service(ts);handle_packets(ts, s->probesize);ts->auto_guess = 1; 上面这几行代码是扫描节目信息,首先mpegts_scan_sdt当中调用mpegts_open_section_filter设置了一个SDT表的filter,SDT表当中会有节目的名子,提供商名子等等。接着在mpegts_set_service当中又设置mpegts_open_section_filter设置了一个PAT表filter,PAT表当中会存放节目的SID, PMT_PID,从而可以取到对应的PMT表,然后解板出VIDEO PID, AUDIO PID来,handle_packets就不用看了,上面设置了filter,这里紧跟着就得让filter工作起来了。
pat_cb: …… av_new_program(ts->stream, sid);ts->stop_parse--;mpegts_open_section_filter(ts, pmt_pid, pmt_cb, ts, 1);add_pat_entry(ts, sid);add_pid_to_pmt(ts, sid, 0); //add pat pid to programadd_pid_to_pmt(ts, sid, pmt_pid);……pmt_cb:……switch(stream_type) {case STREAM_TYPE_AUDIO_MPEG1:case STREAM_TYPE_AUDIO_MPEG2:case STREAM_TYPE_VIDEO_MPEG1:case STREAM_TYPE_VIDEO_MPEG2:case STREAM_TYPE_VIDEO_MPEG4:case STREAM_TYPE_VIDEO_H264:case STREAM_TYPE_VIDEO_VC1:case STREAM_TYPE_VIDEO_DIRAC:case STREAM_TYPE_AUDIO_AAC:case STREAM_TYPE_AUDIO_AC3:case STREAM_TYPE_AUDIO_DTS:case STREAM_TYPE_AUDIO_HDMV_DTS:case STREAM_TYPE_SUBTITLE_DVB: if((stream_type == STREAM_TYPE_AUDIO_HDMV_DTS && !has_hdmv_descr) || (stream_type == STREAM_TYPE_VIDEO_DIRAC && !has_dirac_descr)) break; if(ts->pids[pid] && ts->pids[pid]->type == MPEGTS_PES){ pes= ts->pids[pid]->u.pes_filter.opaque; st= pes->st; }else{ if (ts->pids[pid]) mpegts_close_filter(ts, ts->pids[pid]); //wrongly added sdt filter probably pes = add_pes_stream(ts, pid, pcr_pid, stream_type); if (pes) st = new_pes_av_stream(pes, 0); } add_pid_to_pmt(ts, h->id, pid); if(st) av_program_add_stream_index(ts->stream, h->id, st->index); break;default: break;}……
得到每个video, audio的PID,然后就设置成pes filter,到这里基本上获取流的基本信息就已经结束了。下面再来看使用最多的一个函数mpegts_read_packet:
mpegts_read_packet: handle_packets 这是我们刚刚跳过去的函数。 handle_packet 这函数是处理单个包的,所以后面没有s
if (tss->type == MPEGTS_SECTION) { ……
write_section_data(s, tss, p, p_end - p, 0); ……
} else { // Note: The position here points actually behind the current packet. tss->u.pes_filter.pes_cb(tss, p, p_end - p, is_start, pos - ts->raw_packet_size); } 处理每一个包,如果是section包,就调用write_section_data,这个函数里面如果一个PAT, PMT, SDT表已经构成,则会调用刚刚看到的pat_cb, pmt_cb, sdt_cb,分析到这里,已经不用再管section包了,只看pes包,所以一般会调用tss->u.pes_filter.pes_cb,这个函数指针到底是什么呢?在函数add_pes_stream里面可以看到,mpegts_open_pes_filter函数的一个参数mpegts_push_data就是这里的tss->u.pes_filter.pes_cb,好,跟到这个函数里面瞧瞧。
mpegts_push_data: ……
while (buf_size > 0) { switch(pes->state) { case MPEGTS_HEADER: case MPEGTS_PESHEADER_FILL: case MPEGTS_PAYLOAD: ts->stop_parse = 1; return; ……ts->stop_parse = 1意味着一个pes包构成了,所以上面的函数mpegts_read_packet就返回了,这样,一个pes包送上去了,再送到codec去解码,最后送去video或audio输出设置显示了。由些可以看到ts流和avi, mkv这些一样,都是一个容器,真真的数据都是包含在其中的一个一个的串流。
全部回答
  • 1楼网友:鱼芗
  • 2021-03-04 00:55
你把那个ffmpeg库重装一遍吧,肯定是这个的问题
我要举报
如以上回答内容为低俗、色情、不良、暴力、侵权、涉及违法等信息,可以点下面链接进行举报!
点此我要举报以上问答信息
大家都在看
推荐资讯