核心原理
FFmpeg.AutoGen 库提供了 ffmpeg.av_read_pause 和 ffmpeg.av_read_play 两个函数,配合是否处于暂停中的标识位控制循环逻辑,即可实现 RTSP 流的暂停和继续播放。
代码实现
1. 初始化与解码播放
/// <summary>
/// 对读取的264数据包进行解码和转换
/// </summary>
/// <param name="show">解码完成回调函数</param>
/// <param name="url">播放地址,也可以是本地文件地址</param>
public unsafe void Start(ShowBitmap show, string url, out string strResult)
{
strResult = "";
try
{
CanRun = true;
#region ffmpeg 日志
// 设置记录ffmpeg日志级别
ffmpeg.av_log_set_level(ffmpeg.AV_LOG_VERBOSE);
av_log_set_callback logCallback = (p0, level, format, vl) =>
{
if (level > ffmpeg.av_log_get_level()) return;
var lineSize = 1024;
var lineBuffer = stackalloc byte[lineSize];
var printPrefix = 1;
ffmpeg.av_log_format_line(p0, level, format, vl, lineBuffer, lineSize, &printPrefix);
var line = Marshal.PtrToStringAnsi((IntPtr)lineBuffer);
Console.Write(line);
};
ffmpeg.av_log_set_callback(logCallback);
pFormatContext = ffmpeg.avformat_alloc_context();
pFormatContextTemp = pFormatContext;
error;
Stopwatch stopwatch = Stopwatch();
stopwatch.Start();
AVDictionary* options = ;
ffmpeg.av_dict_set(&options, , , );
error = ffmpeg.avformat_open_input(&pFormatContextTemp, url, , &options);
(error != ) ApplicationException(GetErrorMessage(error));
stopwatch.Stop();
Console.Write();
stopwatch = Stopwatch();
stopwatch.Start();
error = ffmpeg.avformat_find_stream_info(pFormatContext, );
(error != ) ApplicationException(GetErrorMessage(error));
stopwatch.Stop();
Console.Write();
AVStream* pStream = , aStream;
( i = ; i < pFormatContext->nb_streams; i++)
{
(pFormatContext->streams[i]->codec->codec_type == AVMediaType.AVMEDIA_TYPE_VIDEO)
{
streamIndex = i;
pStream = pFormatContext->streams[i];
}
(pFormatContext->streams[i]->codec->codec_type == AVMediaType.AVMEDIA_TYPE_AUDIO)
{
aStream = pFormatContext->streams[i];
}
}
(streamIndex == || pStream == ) ApplicationException();
(error < ) ApplicationException(GetErrorMessage(error));
codecContext = *pStream->codec;
width = codecContext.width;
height = codecContext.height;
sourcePixFmt = codecContext.pix_fmt;
codecId = codecContext.codec_id;
destinationPixFmt = AVPixelFormat.AV_PIX_FMT_BGR24;
(sourcePixFmt == AVPixelFormat.AV_PIX_FMT_NONE && codecId == AVCodecID.AV_CODEC_ID_H264)
{
sourcePixFmt = AVPixelFormat.AV_PIX_FMT_YUV420P;
}
pConvertContext = ffmpeg.sws_getContext(width, height, sourcePixFmt, width, height, destinationPixFmt, ffmpeg.SWS_FAST_BILINEAR, , , );
(pConvertContext == ) ApplicationException();
pConvertedFrame = ffmpeg.av_frame_alloc();
convertedFrameBufferSize = ffmpeg.av_image_get_buffer_size(destinationPixFmt, width, height, );
convertedFrameBufferPtr = Marshal.AllocHGlobal(convertedFrameBufferSize);
dstData = byte_ptrArray4();
dstLinesize = int_array4();
ffmpeg.av_image_fill_arrays( dstData, dstLinesize, (*)convertedFrameBufferPtr, destinationPixFmt, width, height, );
pCodec = ffmpeg.avcodec_find_decoder(codecId);
(pCodec == ) ApplicationException();
pCodecContext = &codecContext;
((pCodec->capabilities & ffmpeg.AV_CODEC_CAP_TRUNCATED) == ffmpeg.AV_CODEC_CAP_TRUNCATED)
pCodecContext->flags |= ffmpeg.AV_CODEC_FLAG_TRUNCATED;
error = ffmpeg.avcodec_open2(pCodecContext, pCodec, );
pCodecContext->skip_frame = AVDiscard.AVDISCARD_NONKEY;
pPacket = AVPacket();
packet = &pPacket;
frameNumber = ;
(CanRun)
{
(objLock)
{
(!_isPause)
{
{
{
error = ffmpeg.av_read_frame(pFormatContext, packet);
(error == ffmpeg.AVERROR_EOF) ;
(error < ) ApplicationException(GetErrorMessage(error));
(packet->stream_index != pStream->index) ;
error = ffmpeg.avcodec_send_packet(pCodecContext, packet);
(error < ) ApplicationException(GetErrorMessage(error));
error = ffmpeg.avcodec_receive_frame(pCodecContext, pConvertedFrame);
} (error == ffmpeg.AVERROR(ffmpeg.EAGAIN) && CanRun);
(error == ffmpeg.AVERROR_EOF) ;
(error < ) ApplicationException(GetErrorMessage(error));
(packet->stream_index != pStream->index) ;
ffmpeg.sws_scale(pConvertContext, pConvertedFrame->data, pConvertedFrame->linesize, , height, dstData, dstLinesize);
}
{
ffmpeg.av_packet_unref(packet);
ffmpeg.av_frame_unref(pConvertedFrame);
}
bitmap = Bitmap(width, height, dstLinesize[], PixelFormat.Format24bppRgb, convertedFrameBufferPtr);
show(bitmap);
frameNumber++;
}
}
}
show();
Thread.Sleep();
Marshal.FreeHGlobal(convertedFrameBufferPtr);
ffmpeg.sws_freeContext(pConvertContext);
ffmpeg.av_free(pConvertedFrame);
ffmpeg.avcodec_close(pCodecContext);
ffmpeg.avformat_close_input(&pFormatContextTemp);
}
(Exception ex)
{
strResult = ;
}
}

