この例では、ストリーミングメディアのネットワークRSTPまたはHTTPをフェッチする方法を示し、TSファイルが保存されました。
グローバル変数を定義します。
AVFormatContext *g_inputContext = NULL;
AVFormatContext * g_outputContext;
int64_t g_lastReadPacktTime = 0;
1、メディアファイルの入力を開きます
オープンメディアファイル、メディアファイルは、その中の情報の流れを分析し、データパケットを読み取ります。そのフレームレートの分析。
int OpenInputMediaFile(string inputUrl)
{
//创建一个AVFormatContext类型变量并初始化默认参数
g_inputContext = avformat_alloc_context();
// 取得时间,以毫秒为单位
g_lastReadPacktTime = av_gettime();
// 填写检测是否中止阻塞功能的回调函数。
g_inputContext->interrupt_callback.callback = interrupt_cb;
// 强制以指定格式打开,为NULL时,自动检测其格式。
AVInputFormat *fmt = NULL;
// 强制以指定格式打开,为NULL时,自动检测其格式。
AVDictionary **options = NULL;
// 打开一个输入流(本地文件名或者是网络流地址URL),并解析其头部格式,并把信息填写到g_inputContext中。
int ret = avformat_open_input(&g_inputContext, inputUrl.c_str(), fmt, options);
if (ret < 0)
{
return ret;
}
// 读取媒体文件的数据包,分析其中的流信息。分析其帧率
ret = avformat_find_stream_info(g_inputContext, nullptr);
return ret;
}
2、出力メディアファイルを開きます
int OpenOutputMediaFile(string outUrl)
{
// 创建一个用于输出的格式信息对像(AVFormatContext)
// 格式指定ts
int ret = avformat_alloc_output_context2(&g_outputContext, nullptr, "mpegts", outUrl.c_str());
if (ret < 0)
{
goto Error;
}
// 打开文件 并初始AVIOContext(g_outputContext->pb)
ret = avio_open2(&g_outputContext->pb, outUrl.c_str(), AVIO_FLAG_WRITE, nullptr, nullptr);
if (ret < 0)
{
goto Error;
}
// 找出源媒体中流的信息
for (int i = 0; i < g_inputContext->nb_streams; i++)
{
// 用输入流的编码信息来创建一个流对像,
AVStream * stream = avformat_new_stream(g_outputContext, g_inputContext->streams[i]->codec->codec);
// 把输入流的编码信息拷贝到个输出流对的编码信息中,
ret = avcodec_copy_context(stream->codec, g_inputContext->streams[i]->codec);
if (ret < 0)
{
goto Error;
}
}
// 分配流的私有信息,并把流的头部信息写到输出文件
ret = avformat_write_header(g_outputContext, nullptr);
if (ret < 0)
{
goto Error;
}
return ret;
Error:
// 出错后关闭输出环境变量
if (g_outputContext)
{
for (int i = 0; i < g_outputContext->nb_streams; i++)
{
avcodec_close(g_outputContext->streams[i]->codec);
}
avformat_close_input(&g_outputContext);
}
return ret;
}
3、データの読み出し
shared_ptr<AVPacket> ReadPacketFrame()
{
shared_ptr<AVPacket> packet(static_cast<AVPacket*>(av_malloc(sizeof(AVPacket))), [&](AVPacket *p)
{ av_packet_free(&p);
av_freep(&p); }
);
// 初始化packet
av_init_packet(packet.get());
// 取时间
g_lastReadPacktTime = av_gettime();
// 读入一帧数据到packet
int ret = av_read_frame(g_inputContext, packet.get());
if (ret >= 0)
{
return packet;
}
else
{
return nullptr;
}
}
4、データが出力ファイルに書き込まれます
void av_packet_rescale_ts(AVPacket *pkt, AVRational src_tb, AVRational dst_tb)
{
if (pkt->pts != AV_NOPTS_VALUE)
pkt->pts = av_rescale_q(pkt->pts, src_tb, dst_tb);
if (pkt->dts != AV_NOPTS_VALUE)
pkt->dts = av_rescale_q(pkt->dts, src_tb, dst_tb);
if (pkt->duration > 0)
pkt->duration = av_rescale_q(pkt->duration, src_tb, dst_tb);
}
int WriteFrame(shared_ptr<AVPacket> packet)
{
auto inputStream = inputContext->streams[packet->stream_index];
auto outputStream = outputContext->streams[packet->stream_index];
av_packet_rescale_ts(packet.get(),inputStream->time_base,outputStream->time_base);
return av_interleaved_write_frame(outputContext, packet.get());
}
5、ライブラリの初期化
// 初始化FFMpeg库
void InitFFMpeg()
{
av_register_all(); // 注册所有的编解码器
avfilter_register_all();// 注册所有的滤镜
avformat_network_init();// 初网络组件。
}
6、リソースを閉じます
void CloseInput()
{
if (g_inputContext != nullptr)
{
// 关闭输入环境,释放结构中的资源
avformat_close_input(&g_inputContext);
}
}
void CloseOutput()
{
if (g_outputContext != nullptr)
{
for (int i = 0; i < g_outputContext->nb_streams; i++)
{
AVCodecContext *codecContext = g_outputContext->streams[i]->codec;
// 关闭输出编码器,释放相关的数据。
avcodec_close(codecContext);
}
// 关闭输出环境,释放结构中的资源
avformat_close_input(&g_outputContext);
}
}
図9に示すように、メイン制御処理
int CaptureStream(string mediaURL, string tsFile)
{
InitFFMpeg();
// CCTV1高清:
// http://ivi.bupt.edu.cn/hls/cctv1hd.m3u8
int ret = OpenInputMediaFile(mediaURL);
if (ret >= 0)
{
ret = OpenOutputMediaFile(tsFile);
}
if (ret <0)
goto Error;
int64_t t2 = av_gettime(); // 取时间(单位为
while (true)
{
// 从输入流中读取一个数据包
auto packet = ReadPacketFromSource();
// 从输入流中读取一个数据包
auto packet = ReadPacketFromSource();
if (packet)
{
ret = WritePacket(packet);
}
// 取30秒的媒体流
if ( packet == nullptr || (av_gettime() - t2) > (1000*1000* 30))
{
break;
}
}
Error:
CloseInput(); // 关闭输入
CloseOutput();// 关闭输出
return 0;
}
10、プロジェクトパッケージのダウンロード
コンパイルして実行のx86 - デバッグインチ