一、C# 调用ffmepg
调用C#FFmpeg.AutoGen.下载方法
注意这个版本需要和下载的ffmpeg的版本一致。也就是FFmpeg.AutoGen4.3.1那么下载的ffmpeg的动态链接库也要是4.3.1
ffmpeg下载
http://www.ffmpeg.org/download.html,下载静态共享版的DLL库
二、大华和海康的rtsp取流
//大华和海康rtsp地址可以根据型号去网上查找
例如大华:rtsp://admin:123456abc@10.8.30.50:554/cam/realmonitor?channel=1&subtype=1
根据这个地址可以下载VLC地址,输入上面地址到VLC的王若URL确保能够播放。
能够播放的话,写代码去推流。推流的地址需要了解第三点介绍的SRS推流。
三、SRS推流
http://www.ossrs.net/srs.release/releases/download.html
需要准备一个centos的服务器,安装SRS
根据自己的centos服务选择下载对应的服务
firewall-cmd –zone=public –add-port=9090/tcp –permanent
firewall-cmd –zone=public –add-port=1935/tcp –permanent
firewall-cmd –zone=public –add-port=8080/tcp –permanent
firewall-cmd --reload
- 进入SRS-CentOS6-x86_64-x.x.x目录安装并启动流媒体服务(使用超级用户)
#./INSTALL
#cd /etc/init.d
#./srs start
启动以后推流服务器地址可以为:rtmp://x.x.x.x:1935/xxx
x.x.x.x是推流服务器地址
xxx是推流地址的子目录
四、推流服务器编码
public unsafe void RunPushStream()
{
//开线程推
int time = int.Parse(GetTimeStamp());
playhandle = time;
ThreadMethod(playhandle);
}
unsafe static void ThreadMethod(object number)
{
PushStream pusher = null;
for (int i = 0; i < GlobalVariable.PushStreamList.Count; i++)
{
var pusherTemp = GlobalVariable.PushStreamList[i];
if (pusherTemp.playhandle == (int)number)
{
pusher = GlobalVariable.PushStreamList[i];
//pusher.start_time = ffmpeg.av_gettime();
// pusher.RunPushStream();
}
}
if (pusher == null)
return;
AVOutputFormat* ofmt = null;
AVFormatContext* ifmt_ctx = null, ofmt_ctx = null;
#region ffmpeg 转码
var fmt = ffmpeg.avformat_alloc_context();
int error;
string url = "rtsp://admin:123456abc@10.8.30.50:554/cam/realmonitor?channel=1&subtype=1";
//打开流
error = ffmpeg.avformat_open_input(&fmt, url, null, null);
pusher.pFormatContext = fmt;
//if (error != 0) throw new ApplicationException(GetErrorMessage(error));
// 读取媒体流信息
error = ffmpeg.avformat_find_stream_info(pusher.pFormatContext, null);
// if (error != 0) throw new ApplicationException(GetErrorMessage(error));
for (var i = 0; i < pusher.pFormatContext->nb_streams; i++)
{
if (pusher.pFormatContext->streams[i]->codec->codec_type == AVMediaType.AVMEDIA_TYPE_VIDEO)
{
// pStream = pFormatContext->streams[i];
pusher.videoindex = i;
// ffmpeg.avformat_new_stream(octx, pFormatContext->streams[i]->codec->codec);
// ffmpeg.avcodec_parameters_copy(octx->streams[i]->codecpar, pFormatContext->streams[i]->codecpar);
}
}
ffmpeg.av_dump_format(pusher.pFormatContext, 0, url, 0);
AVPacket packet = new AVPacket();
var pPacket = &packet;
ffmpeg.av_init_packet(pPacket);
int time = int.Parse(pusher.GetTimeStamp());
string outUrl = string.Format("rtmp://192.168.60.129:1935/live/{0}", time);
outUrl = "rtmp://192.168.60.129:1935/live/66";
var octxtm = pusher.octx;
var ret = ffmpeg.avformat_alloc_output_context2(&octxtm, null, "flv", outUrl);
if (ret < 0)
{
Console.WriteLine(error + "\n");
}
// 从格式化上下文获取流索引
pusher.octx = octxtm;
for (var i = 0; i < pusher.pFormatContext->nb_streams; i++)
{
AVStream* in_stream = pusher.pFormatContext->streams[i];
AVStream* out_stream = ffmpeg.avformat_new_stream(pusher.octx, in_stream->codec->codec);
if (out_stream == null)
{
Console.WriteLine("Failed allocating output stream\n");
ret = ffmpeg.AVERROR_UNKNOWN;
goto end;
}
//Copy the settings of AVCodecContext
ret = ffmpeg.avcodec_copy_context(out_stream->codec, in_stream->codec);
if (ret < 0)
{
Console.WriteLine("Failed to copy context from input to output stream codec context\n");
goto end;
}
}
ffmpeg.av_dump_format(pusher.octx, 0, outUrl, 1);
//if (pStream == null) throw new ApplicationException(@"Could not found video stream.");
// 初始化媒体数据包
var frameNumber = 0;
if ((pusher.octx->flags & ffmpeg.AVFMT_NOFILE) == 0)
{
ret = ffmpeg.avio_open(&pusher.octx->pb, outUrl, ffmpeg.AVIO_FLAG_WRITE);
if (ret < 0)
{
// printf("Could not open output URL '%s'", out_filename);
goto end;
}
}
//Write file header
ret = ffmpeg.avformat_write_header(pusher.octx, null);
if (ret < 0)
{
// printf("Error occurred when opening output URL\n");
goto end;
}
ifmt_ctx = pusher.pFormatContext;
ofmt_ctx = pusher.octx;
ofmt = ofmt_ctx->oformat;
//AVPacket pkt;
//var start_time = ffmpeg.av_gettime();
pusher.starttime1 = ffmpeg.av_gettime();
while (pusher.CanRun)
{
AVStream* in_stream, out_stream;
//Get an AVPacket
var pkt = pusher.pkt;
ret = ffmpeg.av_read_frame(ifmt_ctx, &pkt);
if (ret < 0)
break;
pusher.pkt = pkt;
//FIX:No PTS (Example: Raw H.264)
//Simple Write PTS
//rtsp://admin:123456abc@10.8.30.50:554/cam/realmonitor?channel=1&subtype=1
if (pusher.pkt.pts == ffmpeg.AV_NOPTS_VALUE)
{
//Write PTS
AVRational time_base1 = ifmt_ctx->streams[pusher.videoindex]->time_base;
//Duration between 2 frames (us)
double calc_duration = (double)ffmpeg.AV_TIME_BASE / ffmpeg.av_q2d(ifmt_ctx->streams[pusher.videoindex]->r_frame_rate);
//Parameters
pusher.pkt.pts = (long)((double)(pusher.frame_index * calc_duration) / (double)(ffmpeg.av_q2d(time_base1) * ffmpeg.AV_TIME_BASE));
pusher.pkt.dts = pusher.pkt.pts;
pusher.pkt.duration = (long)((double)calc_duration / (double)(ffmpeg.av_q2d(time_base1) * ffmpeg.AV_TIME_BASE));
}
//Important:Delay
if (pusher.pkt.stream_index == pusher.videoindex)
{
AVRational time_base = ifmt_ctx->streams[pusher.videoindex]->time_base;
AVRational time_base_q = new AVRational();
time_base_q.num = 1;
time_base_q.den = ffmpeg.AV_TIME_BASE;
long pts_time = ffmpeg.av_rescale_q(pusher.pkt.dts, time_base, time_base_q);
long now_time = ffmpeg.av_gettime() - pusher.starttime1;
if (pts_time > now_time)
{
//Console.WriteLine(pts_time - now_time);
// if (now_time > 1471268403)
ffmpeg.av_usleep((uint)(pts_time - now_time));
//ffmpeg.av_usleep((uint)(1471268403));
}
}
in_stream = ifmt_ctx->streams[pusher.pkt.stream_index];
out_stream = ofmt_ctx->streams[pusher.pkt.stream_index];
// copy packet
//Convert PTS/DTS
pusher.pkt.pts = ffmpeg.av_rescale_q_rnd(pusher.pkt.pts, in_stream->time_base, out_stream->time_base, (AVRounding)(AVRounding.AV_ROUND_NEAR_INF | AVRounding.AV_ROUND_PASS_MINMAX));
pusher.pkt.dts = ffmpeg.av_rescale_q_rnd(pusher.pkt.dts, in_stream->time_base, out_stream->time_base, (AVRounding)(AVRounding.AV_ROUND_NEAR_INF | AVRounding.AV_ROUND_PASS_MINMAX));
pusher.pkt.duration = ffmpeg.av_rescale_q(pusher.pkt.duration, in_stream->time_base, out_stream->time_base);
pusher.pkt.pos = -1;
//Print to Screen
if (pusher.pkt.stream_index == pusher.videoindex)
{
// Console.WriteLine("Send {0} video frames to output URL\n", pusher.frame_index);
pusher.frame_index++;
}
//ret = av_write_frame(ofmt_ctx, &pkt);
ret = ffmpeg.av_interleaved_write_frame(ofmt_ctx, &pkt);
if (ret < 0)
{
Console.WriteLine("Error muxing packet\n");
// break;
}
ffmpeg.av_free_packet(&pkt);
// pusher.frameNumber++;
}
ffmpeg.av_write_trailer(ofmt_ctx);
end:
var pcont = pusher.pFormatContext;
ffmpeg.avformat_close_input(&pcont);
// ffmpeg.avformat_close_input(&ifmt_ctx);
if (ofmt_ctx != null && (ofmt->flags & ffmpeg.AVFMT_NOFILE) == 0)
ffmpeg.avio_close(ofmt_ctx->pb);
ffmpeg.avformat_free_context(ofmt_ctx);
if (ret < 0 && ret != ffmpeg.AVERROR_EOF)
{
Console.WriteLine("Error occurred.\n");
return;
}
#endregion
}
需要DEMO:可以下载源码,下载后需要修改推流和拉流地址才能正常播放