可编译运行:调用ffmpeg接口,将RTSP流保存为MP4的C代码

简介: 可编译运行:调用ffmpeg接口,将RTSP流保存为MP4的C代码

 当然,也是从网上下载的。经过一番修改编译,运行结果正确。


 由于dts/pts,有的播放器播放速度有所差异。


 这里就直接就共享出来(也可以去下载区下载)。


头文件

#ifndef __GH_RTSP_2_MP4_H__
#define __GH_RTSP_2_MP4_H__
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#include <libavcodec/avcodec.h>
#include <libavdevice/avdevice.h>
#include <libavformat/avformat.h>
#include <libavfilter/avfilter.h>
#include <libavutil/avutil.h>
#include <libswscale/swscale.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#ifdef __cplusplus
}
#endif
#endif


C源码

#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include "gh_rtsp2mp4.h"
#define RTSP "rtsp://admin:quantum7@192.168.1.144"
//经过实验,这个值最好
#define PTS_VALUE 4500
#define MAX_FRAMES 300
static bool g_RunningFlag = true;
static int rtsp2mp4(const char* pInputFileName, const char* pOutputFileName)
{
    AVOutputFormat *ofmt = NULL;
    //Input AVFormatContext and Output AVFormatContext
    AVFormatContext *ifmt_ctx = NULL, *ofmt_ctx = NULL;
    AVPacket pkt;
    int ret=0, i=0;
    int video_index = -1;
    int frame_index = 0;
    int dts = 0;
    int pts = 0;
    av_register_all();
    //Network
    avformat_network_init();
    //Input
    if ((ret = avformat_open_input(&ifmt_ctx, pInputFileName, 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)
        {
            video_index = i;
            break;
        }
    }
    av_dump_format(ifmt_ctx, 0, pInputFileName, 0);
    //Output
    avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, pOutputFileName); //RTMP
    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;
        }
        //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 |= AV_CODEC_FLAG_GLOBAL_HEADER;
        }
    }
    //Dump Format------------------
    av_dump_format(ofmt_ctx, 0, pOutputFileName, 1);
    //Open output URL
    if (!(ofmt->flags & AVFMT_NOFILE))
    {
        ret = avio_open(&ofmt_ctx->pb, pOutputFileName, AVIO_FLAG_WRITE);
        if (ret < 0)
        {
            printf("Could not open output URL '%s'", pOutputFileName);
            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;
    }
    #if USE_H264BSF
        AVBitStreamFilterContext* h264bsfc = av_bitstream_filter_init("h264_mp4toannexb");
    #endif
    while (g_RunningFlag)
    {
        AVStream *in_stream, *out_stream;
        //Get an AVPacket
        ret = av_read_frame(ifmt_ctx, &pkt);
        if (ret < 0)
        {
            break;
        }
        in_stream  = ifmt_ctx->streams[pkt.stream_index];
        out_stream = ofmt_ctx->streams[pkt.stream_index];
        //Convert PTS/DTS
#if 1
        if (pts == 0)
        {
            pts = pkt.pts;
            dts = pkt.dts;
        }
        else
        {
            pkt.pts += pts;
            pkt.dts += dts;
        }
        if (pkt.dts < pkt.pts)
        {
            pkt.dts = pkt.pts;
        }
#else
        pkt.pts += 4500*frame_index;
        pkt.dts += 4500*frame_index;
#endif
        pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);
        pkt.pos = -1;
        if (pkt.stream_index == video_index)
        {
            //printf("Receive %8d video frames from RTSP\n", frame_index);
            frame_index++;
    #if USE_H264BSF
                av_bitstream_filter_filter(h264bsfc, in_stream->codec, NULL, &pkt.data, &pkt.size, pkt.data, pkt.size, 0);
    #endif
        }
        ret = av_interleaved_write_frame(ofmt_ctx, &pkt);
        if (ret < 0 && frame_index > 3)
        {
            printf("Error muxing packet\n");
            break;
        }
        av_free_packet(&pkt);
        if (frame_index > MAX_FRAMES)
        {
            break;
        }
    }
    #if USE_H264BSF
        av_bitstream_filter_close(h264bsfc);
    #endif
    //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;
}
int main(int argc, char **argv)
{
    rtsp2mp4(RTSP, "rtsp.mp4");
    return 0;
}


Makefile

APP:= gh_rtsp2mp4
SRCS:= gh_rtsp2mp4.cpp
INCS:= $(wildcard *.h)
OBJS:= $(SRCS:.cpp=.o)
#GST
CPPFLAGS+=  -DGST_FLAG \
    -I/usr/local/include
LIBS := -L /usr/lib/x86_64-linux-gnu -lavcodec -lavutil -lswresample -lavformat \
  -L /usr/linclude -lz -llzma -lbz2
# -L /usr/local/lib -lopencv_core -lopencv_imgcodecs -lopencv_imgproc -lopencv_highgui \
LIBS += $(GLLINK)
# LIBS += -lGL -lGLU -lglut
#LIBS+= `pkg-config --libs $(PKGS)`
all: $(APP)
.o: .cpp $(INCS) Makefile
  g++ -g -c $@ $(CPPFLAGS) $<
$(APP): $(OBJS) Makefile
  g++ -g -o $(APP) $(OBJS) $(LIBS)
clean:
  rm -rf $(OBJS) $(APP)
目录
相关文章
|
3月前
|
应用服务中间件 Linux nginx
FFmpeg学习笔记(一):实现rtsp推流rtmp以及ffplay完成拉流操作
这篇博客介绍了如何使用FFmpeg实现RTSP推流到RTMP服务器,并使用ffplay进行拉流操作,包括在Windows和Linux系统下的命令示例,以及如何通过HTML页面显示视频流。
596 0
|
5月前
|
编解码 Linux
CentOS安装ffmpeg并转码视频为mp4
CentOS安装ffmpeg并转码视频为mp4
163 0
|
2月前
|
编解码 监控 网络协议
如何使用FFmpeg实现RTSP推送H.264和H.265(HEVC)编码视频
本文详细介绍了如何使用FFmpeg实现RTSP推送H.264和H.265(HEVC)编码视频。内容涵盖环境搭建、编码配置、服务器端与客户端实现等方面,适合视频监控系统和直播平台等应用场景。通过具体命令和示例代码,帮助读者快速上手并实现目标。
351 6
|
3月前
|
缓存 并行计算 Ubuntu
Jetson 学习笔记(十一):jetson agx xavier 源码编译ffmpeg(3.4.1)和opencv(3.4.0)
本文是关于在Jetson AGX Xavier上编译FFmpeg(3.4.1)和OpenCV(3.4.0)的详细教程,包括编译需求、步骤、测试和可能遇到的问题及其解决方案。还提供了Jetson AGX Xavier编译CUDA版本的OpenCV 4.5.0的相关信息。
99 4
Jetson 学习笔记(十一):jetson agx xavier 源码编译ffmpeg(3.4.1)和opencv(3.4.0)
|
3月前
|
Ubuntu 应用服务中间件 nginx
Ubuntu安装笔记(三):ffmpeg(3.2.16)源码编译opencv(3.4.0)
本文是关于Ubuntu系统中使用ffmpeg 3.2.16源码编译OpenCV 3.4.0的安装笔记,包括安装ffmpeg、编译OpenCV、卸载OpenCV以及常见报错处理。
233 2
Ubuntu安装笔记(三):ffmpeg(3.2.16)源码编译opencv(3.4.0)
|
3月前
|
Linux API 开发工具
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
ijkplayer是由B站研发的移动端播放器,基于FFmpeg 3.4,支持Android和iOS。其源码托管于GitHub,截至2024年9月15日,获得了3.24万星标和0.81万分支,尽管已停止更新6年。本文档介绍了如何在Linux环境下编译ijkplayer的so库,以便在较新的开发环境中使用。首先需安装编译工具并调整/tmp分区大小,接着下载并安装Android SDK和NDK,最后下载ijkplayer源码并编译。详细步骤包括环境准备、工具安装及库编译等。更多FFmpeg开发知识可参考相关书籍。
119 0
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
|
3月前
|
缓存 监控 计算机视觉
视频监控笔记(三):opencv结合ffmpeg获取rtsp摄像头相关信息
本文介绍了如何使用OpenCV结合FFmpeg获取RTSP摄像头信息,包括网络架构、视频监控系统组成、以及如何读取和显示网络摄像头视频流。
96 1
|
3月前
|
Linux 视频直播
FFmpeg开发笔记(五十四)使用EasyPusher实现移动端的RTSP直播
本文介绍了如何使用EasyPusher-Android实现RTSP直播流程。首先对比了RTSP、RTMP、SRT和RIST四种流媒体协议,并以RTSP为例,详细说明了使用EasyPusher-Android向流媒体服务器进行RTSP直播推流的方法。文中还提供了OBS Studio配置RTSP插件及ZLMediaKit云服务器部署的相关信息,通过修改EasyPusher-Android源码使其支持通用RTSP地址,最终验证了直播功能的成功实现。
83 0
FFmpeg开发笔记(五十四)使用EasyPusher实现移动端的RTSP直播
|
4月前
|
编解码 API 数据安全/隐私保护
FFmpeg开发笔记(五十四)使用EasyPusher实现移动端的RTSP直播
【9月更文挑战第21天】本文介绍了如何使用FFmpeg和EasyPusher实现移动端RTSP直播。首先概述了EasyPusher的功能及其API,接着详细描述了安装FFmpeg、获取EasyPusher库、初始化对象、打开输入流、配置推送参数及读取推送帧的具体步骤,并提醒开发者注意网络环境、编码参数和权限管理等问题,以确保直播质量与稳定性。
|
3月前
FFmpeg学习笔记(二):多线程rtsp推流和ffplay拉流操作,并储存为多路avi格式的视频
这篇博客主要介绍了如何使用FFmpeg进行多线程RTSP推流和ffplay拉流操作,以及如何将视频流保存为多路AVI格式的视频文件。
377 0