在本文中主要讲如何用FFMPEG编写RTP的推流程序和打视音频时间戳上的问题
PS:文中代码基于LINUX
一. 文件的打开和输出流的打开
用avformat_open_input分别打开视音频文件,用avformat_alloc_output_context2打开输出的RTP流,注意,这里用的选项是rtp_mpegts,代表的是传输的视音频数据会打包成TS流的形式进行发送。rtp一个端口只能传输一路数据,所以我这里开了两个rtp端口,分别传输视音频数据。
avformat_open_input(&ifmt_ctx_v, in_filename_v, 0, 0);
avformat_open_input(&ifmt_ctx_a, in_filename_a, 0, 0);
avformat_alloc_output_context2(ofmt_ctx, NULL, "rtp_mpegts", NULL);
avformat_alloc_output_context2(ofmt_ctx+1, NULL, "rtp_mpegts", NULL);
二. 读取视音频数据并打上时间戳
av_compare_ts两个不同时基的时间戳,谁的比较大。
通过av_compare_ts决定要读取音频数据还是视频数据,当音频时间戳比较大的时候就读取视频数据,当视频时间戳比较大的时候就读取音频时间戳。
1. 视频时间戳
AVRational time_base = in_stream->time_base;//{ 1, 1000 };
AVRational r_framerate1 = in_stream->r_frame_rate;
AVRational time_base_q = { 1, AV_TIME_BASE };
//Duration between 2 frames (us)
int64_t calc_duration = (double)(AV_TIME_BASE) / av_q2d(r_framerate1); //内部时间戳
pkt.pts = av_rescale_q(vframe_index*calc_duration, time_base_q, time_base);
pkt.dts = pkt.pts;
pkt.duration = av_rescale_q(calc_duration, time_base_q, time_base);
pkt.pos = -1;
pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, (enum AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, (enum AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);
pkt.pos = -1;
av_q2d(a) ——————— 把AVRatioal结构a转换成double的函数
av_rescale_q(a,b,c) ——– 把a从b时基转换成c时基
上面的一大堆代码其实是在不同的时基上大时间戳后,进行转换。
首先是这段代码
AVRational time_base1=in_stream->time_base;
AVRational time_base_q = { 1, AV_TIME_BASE };
double frame_size = (double)in_stream->codec->frame_size;
double sample_rate = (double)in_stream->codec->sample_rate;
//Duration between 2 frames (us)
int64_t calc_duration=(double)(AV_TIME_BASE) * (frame_size/sample_rate);
pkt.pts = av_rescale_q(aframe_index*calc_duration, time_base_q, time_base1);
pkt.dts = pkt.pts;
pkt.duration = av_rescale_q(calc_duration, time_base_q, time_base1);
pkt.pos = -1;
在视频文件时钟的时基上打时间戳,然后进行时间戳的转换,把时间戳转换为RTP的时基单位。
pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, (enum AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, (enum AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);
pkt.pos = -1;
减去那些时钟转化的步骤其实就是
pkt.pts &#