简介
- ffmpeg C开发 常用技巧
ffmpeg AVPacket 初始化和反初始化
- av_init_packet()函数被弃用了
- 应该使用 av_packet_alloc()函数对packet进行申请,使用av_packet_free()函数继续释放
ffmpeg AVFrame 转 cv::Mat
- 上面函数传入的参数frame中的图像格式,可以是YUV, RGB ,等等,,经过sws_scale()转换之后,写入cv::Mat 数据区。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
//AVFrame 转 cv::mat cv::Mat frame_to_mat(const AVFrame * frame) { int width = frame->width; int height = frame->height; cv::Mat image(height, width, CV_8UC3); int cvLinesizes[1]; cvLinesizes[0] = image.step1(); if( NULL == _swsContext) { _swsContext = sws_getContext(width, height, (AVPixelFormat)frame->format, width, height, AVPixelFormat::AV_PIX_FMT_BGR24, SWS_FAST_BILINEAR, NULL, NULL, NULL); } sws_scale(_swsContext, frame->data, frame->linesize, 0, height, &image.data, cvLinesizes); return image; }
- 还有一种方式 是直接将AVFrame 中的RGB数据赋值给cv::Mat
1 2 3
cv::Mat img; img = cv::Mat(height, width, CV_8UC3); img.data = _rgb_frame->data[0];
ffmpeg开发库 C++ 输入rtsp流地址 录制指定长度的视频到本地 编程示例
要使用FFmpeg的C++开发库来录制指定长度的RTSP流视频到本地,你可以使用libavcodec、libavformat等库来完成。下面是一个简单的示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/time.h>
}
int main() {
// av_register_all(); // 新版本弃用
avformat_network_init();
AVFormatContext *pFormatCtx = avformat_alloc_context();
AVDictionary *options = NULL;
av_dict_set(&options, "rtsp_transport", "tcp", 0);
const char *rtsp_url = "rtsp://example.com/stream"; // RTSP流地址
const char *output_file = "output.mp4"; // 输出文件名
int duration = 60; // 录制时长(秒)
if (avformat_open_input(&pFormatCtx, rtsp_url, NULL, &options) != 0) {
std::cerr << "无法打开RTSP流" << std::endl;
return -1;
}
if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
std::cerr << "无法获取流信息" << std::endl;
return -1;
}
AVFormatContext *pOutputFormatCtx;
if (avformat_alloc_output_context2(&pOutputFormatCtx, NULL, NULL, output_file) < 0) {
std::cerr << "无法分配输出格式上下文" << std::endl;
return -1;
}
AVStream *pStream = avformat_new_stream(pOutputFormatCtx, NULL);
if (!pStream) {
std::cerr << "无法创建输出流" << std::endl;
return -1;
}
if (avcodec_parameters_copy(pStream->codecpar, pFormatCtx->streams[0]->codecpar) < 0) {
std::cerr << "无法拷贝编解码参数" << std::endl;
return -1;
}
if (!(pOutputFormatCtx->oformat->flags & AVFMT_NOFILE)) {
if (avio_open(&pOutputFormatCtx->pb, output_file, AVIO_FLAG_WRITE) < 0) {
std::cerr << "无法打开输出文件" << std::endl;
return -1;
}
}
avformat_write_header(pOutputFormatCtx, NULL);
AVPacket packet;
int64_t startTime = av_gettime();
int64_t endTime = startTime + duration * 1000000;
while (av_read_frame(pFormatCtx, &packet) >= 0) {
if (av_gettime() >= endTime) {
break;
}
av_packet_rescale_ts(&packet, pFormatCtx->streams[0]->time_base, pStream->time_base);
packet.stream_index = pStream->index;
av_interleaved_write_frame(pOutputFormatCtx, &packet);
av_packet_unref(&packet);
}
av_write_trailer(pOutputFormatCtx);
avformat_close_input(&pFormatCtx);
avio_closep(&pOutputFormatCtx->pb);
avformat_free_context(pOutputFormatCtx);
av_dict_free(&options);
return 0;
}
在这个示例中,我们首先初始化了FFmpeg库,然后打开了指定的RTSP流。我们创建了一个输出格式上下文,并且设置了输出文件名。然后,我们复制了输入流的编解码参数到输出流,接着开始逐帧读取输入流,并将其写入输出流。当录制时长达到指定时长后,我们退出录制,并释放相关资源。请确保将 rtsp_url
替换为你的 RTSP 流地址,output_file
为输出文件的路径和名称,duration
为录制时长(以秒为单位)。