环境:
ffmpeg版本:n4.2.2
下载地址(下载编译后请确认版本正确):
https://ffmpeg.org//download.html
下面地址经过第三方git加速可能存在实效性:
https://hub.fgit.cf/ffmpeg/ffmpeg/tree/n4.4.2
实现代码:
#include <stdio.h>
#define __stdc_constant_macros
#ifdef _win32
//windows
extern "c"
{
#include "libavformat/avformat.h"
#include "libavutil/mathematics.h"
#include "libavutil/time.h"
};
#else
//linux...
#ifdef __cplusplus
extern "c"
{
#endif
#include <libavformat/avformat.h>
#include <libavutil/mathematics.h>
#include <libavutil/time.h>
#ifdef __cplusplus
};
#endif
#endif
#define codec_flag_global_header 0x00400000
int main(int argc, char* argv[])
{
avoutputformat *ofmt = null;
//输入对应一个avformatcontext,输出对应一个avformatcontext
//(input avformatcontext and output avformatcontext)
avformatcontext *ifmt_ctx = null, *ofmt_ctx = null;
avpacket pkt;
const char *in_filename, *out_filename;
int ret, i;
int videoindex=-1;
int frame_index=0;
int64_t start_time=0;
in_filename = "test.mp4";//输入url(input file url)
out_filename = "rtmp://192.168.110.79:1935/live/1";//输出 url(output url)[rtmp]
av_register_all();
//network
avformat_network_init();
//输入(input)
if ((ret = avformat_open_input(&ifmt_ctx, in_filename, 0, 0)) < 0) {
printf( "could not open input file.");
goto end;
}
if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) {
printf( "failed to retrieve input stream information");
goto end;
}
for(i=0; i<ifmt_ctx->nb_streams; i++)
if(ifmt_ctx->streams[i]->codec->codec_type==avmedia_type_video){
videoindex=i;
break;
}
av_dump_format(ifmt_ctx, 0, in_filename, 0);
//输出(output)
avformat_alloc_output_context2(&ofmt_ctx, null, "flv", out_filename); //rtmp
//avformat_alloc_output_context2(&ofmt_ctx, null, "mpegts", out_filename);//udp
if (!ofmt_ctx) {
printf( "could not create output context\n");
ret = averror_unknown;
goto end;
}
ofmt = ofmt_ctx->oformat;
for (i = 0; i < ifmt_ctx->nb_streams; i++) {
//根据输入流创建输出流(create output avstream according to input avstream)
avstream *in_stream = ifmt_ctx->streams[i];
avstream *out_stream = avformat_new_stream(ofmt_ctx, in_stream->codec->codec);
if (!out_stream) {
printf( "failed allocating output stream\n");
ret = averror_unknown;
goto end;
}
//复制avcodeccontext的设置(copy the settings of avcodeccontext)
ret = avcodec_copy_context(out_stream->codec, in_stream->codec);
if (ret < 0) {
printf( "failed to copy context from input to output stream codec context\n");
goto end;
}
out_stream->codec->codec_tag = 0;
if (ofmt_ctx->oformat->flags & avfmt_globalheader)
out_stream->codec->flags |= codec_flag_global_header;
}
//dump format------------------
av_dump_format(ofmt_ctx, 0, out_filename, 1);
//打开输出url(open output url)
if (!(ofmt->flags & avfmt_nofile)) {
ret = avio_open(&ofmt_ctx->pb, out_filename, avio_flag_write);
if (ret < 0) {
printf( "could not open output url '%s'", out_filename);
goto end;
}
}
//写文件头(write file header)
ret = avformat_write_header(ofmt_ctx, null);
if (ret < 0) {
printf( "error occurred when opening output url\n");
goto end;
}
start_time=av_gettime();
while (1) {
avstream *in_stream, *out_stream;
//获取一个avpacket(get an avpacket)
ret = av_read_frame(ifmt_ctx, &pkt);
if (ret < 0)
break;
//fix:no pts (example: raw h.264)
//simple write pts
if(pkt.pts==av_nopts_value){
//write pts
avrational time_base1=ifmt_ctx->streams[videoindex]->time_base;
//duration between 2 frames (us)
int64_t calc_duration=(double)av_time_base/av_q2d(ifmt_ctx->streams[videoindex]->r_frame_rate);
//parameters
pkt.pts=(double)(frame_index*calc_duration)/(double)(av_q2d(time_base1)*av_time_base);
pkt.dts=pkt.pts;
pkt.duration=(double)calc_duration/(double)(av_q2d(time_base1)*av_time_base);
}
//important:delay
if(pkt.stream_index==videoindex){
avrational time_base=ifmt_ctx->streams[videoindex]->time_base;
avrational time_base_q={1,av_time_base};
int64_t pts_time = av_rescale_q(pkt.dts, time_base, time_base_q);
int64_t now_time = av_gettime() - start_time;
if (pts_time > now_time)
av_usleep(pts_time - now_time);
}
in_stream = ifmt_ctx->streams[pkt.stream_index];
out_stream = ofmt_ctx->streams[pkt.stream_index];
/* copy packet */
//转换pts/dts(convert pts/dts)
pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, (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, (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;
//print to screen
if(pkt.stream_index==videoindex){
printf("send %8d video frames to output url\n",frame_index);
frame_index++;
}
//ret = av_write_frame(ofmt_ctx, &pkt);
ret = av_interleaved_write_frame(ofmt_ctx, &pkt);
if (ret < 0) {
printf( "error muxing packet\n");
break;
}
av_free_packet(&pkt);
}
//写文件尾(write file trailer)
av_write_trailer(ofmt_ctx);
end:
avformat_close_input(&ifmt_ctx);
/* close output */
if (ofmt_ctx && !(ofmt->flags & avfmt_nofile))
avio_close(ofmt_ctx->pb);
avformat_free_context(ofmt_ctx);
if (ret < 0 && ret != averror_eof) {
printf( "error occurred.\n");
return -1;
}
return 0;
}
cmake:
cmake_minimum_required(version 3.10.2)
project(w_test)
set(cmake_c_compiler /mnt/sda2/rk3588_sdk/other/rk3566_gcc_tool/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-gcc)
set(cmake_cxx_compiler /mnt/sda2/rk3588_sdk/other/rk3566_gcc_tool/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-g++)
set(cmake_strip /mnt/sda2/rk3588_sdk/other/rk3566_gcc_tool/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-strip)
set(ffmpeg_libs_dir /home/rog/my_file/other_lib/myffmpeg/4.2.2/ffmpeg/my_lib_arm/lib)
set(ffmpeg_headers_dir /home/rog/my_file/other_lib/myffmpeg/4.2.2/ffmpeg/my_lib_arm/include)
add_library( avcodec shared imported)
add_library( avfilter shared imported )
add_library( swresample shared imported )
add_library( swscale shared imported )
add_library( avformat shared imported )
add_library( avutil shared imported )
set_target_properties( avcodec properties imported_location ${ffmpeg_libs_dir}/libavcodec.so )
set_target_properties( avfilter properties imported_location ${ffmpeg_libs_dir}/libavfilter.so )
set_target_properties( swresample properties imported_location ${ffmpeg_libs_dir}/libswresample.so )
set_target_properties( swscale properties imported_location ${ffmpeg_libs_dir}/libswscale.so )
set_target_properties( avformat properties imported_location ${ffmpeg_libs_dir}/libavformat.so )
set_target_properties( avutil properties imported_location ${ffmpeg_libs_dir}/libavutil.so )
include_directories( ${ffmpeg_headers_dir} )
link_directories(${ffmpeg_libs_dir} )
set(cmake_cxx_standard 14)
add_executable(w_test main.cpp)
target_link_libraries(${project_name} ${opencv_libs} avcodec avformat avutil swresample swscale swscale avfilter )
效果:
摄像头推流代码:
#include <iostream>
#include <csignal>
#include <opencv2/opencv.hpp>
bool is_running = true;
void onsignal(int)
{
is_running = false;
}
int main()
{
// 触发下面的信号就退出
signal(sigint, onsignal);
signal(sigquit, onsignal);
signal(sigterm, onsignal);
// 打开摄像头
cv::videocapture capture("/dev/video21");
if (!capture.isopened())
{
std::cerr << "failed to open camera." << std::endl;
return exit_failure;
}
capture.set(cv::cap_prop_frame_width, 1280);
capture.set(cv::cap_prop_frame_height, 720);
std::string rtmp_server_url = "rtmp://192.168.110.79:1935/live/1";
std::stringstream command;
command << "ffmpeg ";
// infile options
command << "-y " // 覆盖输出文件
<< "-an " // 禁用音频
<< "-f rawvideo " // 强制将格式转换为rawvideo
<< "-vcodec rawvideo " // 强制视频rawvideo(“复制”到复制流)
<< "-pix_fmt bgr24 " // 将像素格式设置为bgr24
<< "-s 1280x720 " // 设置帧大小(wxh或缩写)
<< "-r 10 "; // 设置帧速率(hz值、分数或缩写)
command
<< "-i - "; //
// outfile options
command //<< "-c:v libx264 " // 超高速音频和视频编码器 按照需要选择是否打开注释,打开延时比较大
<< "-pix_fmt yuv420p " // 将像素格式设置为yuv420p
//<< "-preset ultrafast " // 将libx264编码预设设置为超快 按照需要选择是否打开注释,打开延时比较大
<< "-f flv " // 将格式强制为flv
<< rtmp_server_url;
std::cout << "------------command:" << command.str() << std::endl;
cv::mat frame;
// 在子进程中调用 ffmpeg 进行推流
file *fp = nullptr;
fp = popen(command.str().c_str(), "w");
// 将 cv 读到的每一帧传入子进程
if (fp != nullptr)
{
while (is_running)
{
capture >> frame;
if (frame.empty())
{
continue;
}
fwrite(frame.data, sizeof(char), frame.total() * frame.elemsize(), fp);
}
pclose(fp);
return exit_success;
}
else
{
return exit_failure;
}
}
对应的cmake
cmake_minimum_required(version 3.10.2)
project(w_test)
set(cmake_install_rpath /userdata/obj/lib)
set(cmake_c_compiler /mnt/sda2/rk3588_sdk/other/rk3566_gcc_tool/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-gcc)
set(cmake_cxx_compiler /mnt/sda2/rk3588_sdk/other/rk3566_gcc_tool/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-g++)
set(cmake_strip /mnt/sda2/rk3588_sdk/other/rk3566_gcc_tool/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-strip)
set(cmake_prefix_path /home/rog/my_file/other_lib/my_opencv/4.8.0_arm/opencv/my_lib_rk3588/lib/cmake/opencv4)
find_package( opencv 4.8.0 required )
include_directories(${opencv_include_dirs})
set(ffmpeg_libs_dir /home/rog/my_file/other_lib/myffmpeg/4.2.2/ffmpeg/my_lib_arm/lib)
set(ffmpeg_headers_dir /home/rog/my_file/other_lib/myffmpeg/4.2.2/ffmpeg/my_lib_arm/include)
set(x264_libs_dir /home/rog/my_file/other_lib/myffmpeg/x264-master/my_lib/lib)
set(x264_headers_dir /home/rog/my_file/other_lib/myffmpeg/x264-master/my_lib/include)
add_library( avcodec shared imported)
add_library( avfilter shared imported )
add_library( swresample shared imported )
add_library( swscale shared imported )
add_library( avformat shared imported )
add_library( avutil shared imported )
set_target_properties( avcodec properties imported_location ${ffmpeg_libs_dir}/libavcodec.so )
set_target_properties( avfilter properties imported_location ${ffmpeg_libs_dir}/libavfilter.so )
set_target_properties( swresample properties imported_location ${ffmpeg_libs_dir}/libswresample.so )
set_target_properties( swscale properties imported_location ${ffmpeg_libs_dir}/libswscale.so )
set_target_properties( avformat properties imported_location ${ffmpeg_libs_dir}/libavformat.so )
set_target_properties( avutil properties imported_location ${ffmpeg_libs_dir}/libavutil.so )
include_directories( ${ffmpeg_headers_dir} )
link_directories(${ffmpeg_libs_dir} )
include_directories( ${x264_headers_dir} )
link_directories(${x264_libs_dir} )
set(cmake_cxx_standard 14)
add_executable(w_test main.cpp)
target_link_libraries(${project_name} ${opencv_libs} avcodec avformat avutil swresample swscale swscale avfilter postproc x264 )
发表评论