编辑
2024-08-16
嵌入式
00
请注意,本文编写于 155 天前,最后修改于 84 天前,其中某些信息可能已经过时。

C++使用FFmpeg读取UVC摄像头推流,流媒体服务器用Go实现,摄像头是USB免驱摄像头

关于Go流媒体服务器的实现请看:FFmpe读取UVC摄像头推流

FFmpeg版本:n7.1

注意链接库的顺序:

avformat avcodec avdevice avfilter avutil swresample swscale

C++
extern "C" { #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libavutil/imgutils.h> #include <libswscale/swscale.h> #include "libavdevice/avdevice.h" } int main() { // 初始化FFmpeg库 avdevice_register_all(); avformat_network_init(); // 打开视频设备 AVFormatContext *input_ctx = nullptr; AVDictionary *options = nullptr; av_dict_set(&options, "input_format", "mjpeg", 0); if (avformat_open_input(&input_ctx, "/dev/video0", nullptr, &options) < 0) { fprintf(stderr, "无法打开视频输入设备。\n"); return -1; } // 查找视频流 if (avformat_find_stream_info(input_ctx, nullptr) < 0) { fprintf(stderr, "无法获取视频流信息。\n"); return -1; } // 创建一个用于接收解码器的指针变量 const AVCodec *decoder = nullptr; // 使用二级指针传递 decoder 变量的地址 int video_stream_index = av_find_best_stream(input_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &decoder, 0); if (video_stream_index < 0) { fprintf(stderr, "无法找到视频流。\n"); return -1; } // 打开解码器 AVCodecContext *decoder_ctx = avcodec_alloc_context3(decoder); avcodec_parameters_to_context(decoder_ctx, input_ctx->streams[video_stream_index]->codecpar); if (avcodec_open2(decoder_ctx, decoder, nullptr) < 0) { fprintf(stderr, "无法打开解码器。\n"); return -1; } // 创建输出格式上下文 AVFormatContext *output_ctx = nullptr; avformat_alloc_output_context2(&output_ctx, nullptr, "rtsp", "rtsp://192.168.1.31:8554/live.sdp"); if (!output_ctx) { fprintf(stderr, "无法创建输出上下文。\n"); return -1; } // 设置编码器 const AVCodec *encoder = avcodec_find_encoder(AV_CODEC_ID_MPEG4); AVCodecContext *encoder_ctx = avcodec_alloc_context3(encoder); encoder_ctx->bit_rate = 400000; encoder_ctx->width = decoder_ctx->width; encoder_ctx->height = decoder_ctx->height; encoder_ctx->time_base = {1, 25}; encoder_ctx->framerate = {25, 1}; encoder_ctx->gop_size = 10; encoder_ctx->max_b_frames = 1; encoder_ctx->pix_fmt = AV_PIX_FMT_YUV420P; av_opt_set(encoder_ctx->priv_data, "preset", "ultrafast", 0); av_opt_set(encoder_ctx->priv_data, "tune", "zerolatency", 0); if (avcodec_open2(encoder_ctx, encoder, nullptr) < 0) { fprintf(stderr, "无法打开编码器。\n"); return -1; } // 创建并添加输出流 AVStream *out_stream = avformat_new_stream(output_ctx, nullptr); avcodec_parameters_from_context(out_stream->codecpar, encoder_ctx); // 打开输出URL if (!(output_ctx->oformat->flags & AVFMT_NOFILE)) { if (avio_open(&output_ctx->pb, "rtsp://192.168.129.191:8554/live.sdp", AVIO_FLAG_WRITE) < 0) { fprintf(stderr, "无法打开输出文件。\n"); return -1; } } // 写文件头 avformat_write_header(output_ctx, nullptr); // 初始化帧数据和转换器 AVFrame *frame = av_frame_alloc(); AVPacket *packet = av_packet_alloc(); AVFrame *yuv_frame = av_frame_alloc(); yuv_frame->format = encoder_ctx->pix_fmt; yuv_frame->width = encoder_ctx->width; yuv_frame->height = encoder_ctx->height; av_frame_get_buffer(yuv_frame, 0); struct SwsContext *sws_ctx = sws_getContext(decoder_ctx->width, decoder_ctx->height, decoder_ctx->pix_fmt, encoder_ctx->width, encoder_ctx->height, encoder_ctx->pix_fmt, SWS_BICUBIC, nullptr, nullptr, nullptr); // 循环读取并编码帧 while (av_read_frame(input_ctx, packet) >= 0) { if (packet->stream_index == video_stream_index) { if (avcodec_send_packet(decoder_ctx, packet) == 0) { while (avcodec_receive_frame(decoder_ctx, frame) == 0) { // 转换帧格式 sws_scale(sws_ctx, frame->data, frame->linesize, 0, frame->height, yuv_frame->data, yuv_frame->linesize); // 发送帧到编码器 if (avcodec_send_frame(encoder_ctx, yuv_frame) == 0) { AVPacket encoded_pkt; av_init_packet(&encoded_pkt); encoded_pkt.data = nullptr; encoded_pkt.size = 0; while (avcodec_receive_packet(encoder_ctx, &encoded_pkt) == 0) { // 推送编码后的数据 encoded_pkt.stream_index = out_stream->index; av_interleaved_write_frame(output_ctx, &encoded_pkt); av_packet_unref(&encoded_pkt); } } } } } av_packet_unref(packet); } // 写文件尾并清理资源 av_write_trailer(output_ctx); av_frame_free(&frame); av_frame_free(&yuv_frame); av_packet_free(&packet); avcodec_free_context(&decoder_ctx); avcodec_free_context(&encoder_ctx); avformat_close_input(&input_ctx); avio_closep(&output_ctx->pb); avformat_free_context(output_ctx); sws_freeContext(sws_ctx); avformat_network_deinit(); return 0; }

本文作者:phae

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!