实现用FFmpeg接收RTSP,把H264视频和AAC音频录制成MP4文件(附完整代码)

本文介绍了如何使用FFmpeg库接收RTSP流并将H264视频和AAC音频录制为MP4文件。通过RtspStreamMuxTask类实现,包括初始化组件、设置输入URL和输出路径、接收流及处理时间戳。在接收过程中,处理了连接超时的问题,通过设置异常回调函数中断长时间未响应的连接。
摘要由CSDN通过智能技术生成

  FFmpeg支持Rtsp流接收功能,协议实现已经较为完善,利用FFmpeg还可以将RTSP收到的流录制为某种容器格式。这里我向大家介绍怎么用它的API来实现RTSP接收和录制这两个功能。

   我把接收RTSP和录制文件的逻辑都用一个类RtspStreamMuxTask来处理,下面给出这个类的头文件和源文件。

  RtspStreamMuxTask.h文件:

#ifndef RtspStreamMuxTask_H
#define RtspStreamMuxTask_H

#ifdef __cplusplus
extern "C" {
#endif 

#ifdef HAVE_AV_CONFIG_H
#undef HAVE_AV_CONFIG_H
#endif

#include "./include/libavcodec/avcodec.h"
#include "./include/libavutil/mathematics.h"
#include "./include/libavutil/avutil.h"
#include "./include/libswscale/swscale.h"
#include "./include/libavutil/fifo.h"
#include "./include/libavformat/avformat.h"
#include "./include/libavutil/opt.h"
#include "./include/libavutil/error.h"
#include "./include/libswresample/swresample.h"  
#ifdef __cplusplus
}
#endif

#pragma comment( lib, "avcodec.lib")
#pragma comment( lib, "avutil.lib")
#pragma comment( lib, "avformat.lib")
#pragma comment(lib, "swresample.lib")
#pragma comment( lib, "swscale.lib" )

#ifndef CodecID
#define CodecID AVCodecID
#endif

class RtspStreamMuxTask
{
public:
	RtspStreamMuxTask();
	virtual ~RtspStreamMuxTask();

	void  SetInputUrl(string rtspUrl);
	void  SetOutputPath(string outputPath);

	void StartRecvStream();
	void StopRecvStream();

	void GetVideoSize(long & width, long & height)  //获取视频分辨率
	{
		width  = coded_width;
		height = coded_height;
	}

private:
	void run();

	int  OpenInputStream();
	void CloseInputStream();

	void readAndMux();

	static DWORD WINAPI ReadingThrd(void * pParam);

	int  openOutputStream();
	void closeOutputStream();

	void ReleaseCodecs();

private:

	string m_inputUrl;
	string m_outputFile;

	AVFormatContext* m_inputAVFormatCxt;
	AVBitStreamFilterContext* m_bsfcAAC;
	AVBitStreamFilterContext* m_bsfcH264;

	int m_videoStreamIndex;
	int m_audioStreamIndex;

	AVFormatContext* m_outputAVFormatCxt;

	char m_tmpErrString[64];
	bool m_stop_status;

	HANDLE m_hReadThread;

	BOOL   m_bInputInited;
	BOOL   m_bOutputInited;

	int    coded_width, coded_height;
	int    m_frame_rate;

};

#endif // RtspStreamMuxTask_H

  RtspStreamMuxTask.cpp文件:

#include "stdafx.h"
#include "RtspStreamMuxTask.h"
#include <sstream>


string to_string(int n)
{
	std::ostringstream stm;
	string str;
	stm << n;
	str = stm.str();
	//std::cout << str << std::endl;
	return str;
}

//

RtspStreamMuxTask::RtspStreamMuxTask()
{
    m_stop_status = false;
    m_inputAVFormatCxt = nullptr;
    m_bsfcAAC = nullptr;
	m_bsfcH264 = nullptr;
    m_videoStreamIndex = -1;
	m_audioStreamIndex = -1;
    m_outputAVFormatCxt = nullptr;
	m_hReadThread = NULL;
	m_bInputInited = FALSE;
	m_bOutputInited = FALSE;
    coded_width = coded_height = 0;
    m_frame_rate = 25;

	 /* register all codecs, demux and protocols */
    avcodec_register_all();
    av_register_all();
}

RtspStreamMuxTask::~RtspStreamMuxTask()
{
	StopRecvStream();
}


void  RtspStreamMuxTask::SetInputUrl(string rtspUrl)
{
	m_inputUrl = rtspUrl;
}

void  RtspStreamMuxTask::SetOutputPath(string outputPath)
{
	m_outputFile = outputPath;
}

void RtspStreamMuxTask::StartRecvStream()
{
	if(m_inputUrl.empty())
		return;

    m_videoStreamIndex = -1;
	m_audioStreamIndex = -1;

	m_bInputInited  = FALSE;
	m_bOutputInited = FALSE;

	coded_width = coded_height = 0;

   	DWORD threadID = 0;
	m_hReadThread = CreateThread(NULL, 0, ReadingThrd, this, 0, &threadID);
}


void RtspStreamMuxTask::StopRecvStream()
{
    m_stop_status = true;

	if (m_hReadThread != NULL) 
	{
        WaitForSingleObject(m_hReadThread, INFINITE);
		CloseHandle(m_hReadThread);
		m_hReadThread = NULL;
	}
    CloseInputStream();
}

DWORD WINAPI RtspStreamMuxTask::ReadingThrd(void * pParam)
{
	RtspStreamMuxTask * pTask = (RtspStreamMuxTask *) pParam;

	pTask->run();

	OutputDebugString("ReadingThrd exited\n");

	return 0;
}

void RtspStreamMuxTask::run()
{
    try
    {
        m_stop_status = false;

        OpenInputStream();
		openOutputStream();

        m_stop_status = false;

        readAndMux();

        CloseInputStream();
		closeOutputStream();
       
    }
    catch(std::exception& e)
    {
		TRACE("%s \n", e.what());
        CloseInputStream();
    }
}

int RtspStreamMuxTask::OpenInputStream()
{
    if (m_inputAVFormatCxt)
    {
        string strError  = ("already has input avformat");
		TRACE("%s \n", strError.c_str());
		return -1;
  
以下是一个使用RV1109采集音视频并使用H.264和AAC格式保存本地文件的简单示例。在这个示例中,我们使用了RV1109媒体采集和编码库进行音视频采集和编码,同时使用了FFmpeg库进行H.264和AAC格式的编码和保存。 ```c #include <stdio.h> #include <stdlib.h> #include "media.h" #include "ffencoder.h" #define VIDEO_WIDTH 1280 #define VIDEO_HEIGHT 720 #define VIDEO_FPS 30 #define VIDEO_BITRATE 1000000 #define AUDIO_SAMPLERATE 44100 #define AUDIO_CHANNELS 2 #define AUDIO_BITRATE 64000 #define VIDEO_OUTPUT_FILENAME "video.h264" #define AUDIO_OUTPUT_FILENAME "audio.aac" int main() { /* 初始化音视频采集模块 */ media_init(); /* 配置视频采集参数 */ media_set_video_params(VIDEO_WIDTH, VIDEO_HEIGHT, VIDEO_FPS, VIDEO_BITRATE); /* 配置音频采集参数 */ media_set_audio_params(AUDIO_SAMPLERATE, AUDIO_CHANNELS, AUDIO_BITRATE); /* 创建H.264编码器 */ FFEncoder* video_encoder = ffencoder_create(VIDEO_WIDTH, VIDEO_HEIGHT, VIDEO_BITRATE, 30, CODEC_ID_H264); if (video_encoder == NULL) { printf("Failed to create H.264 encoder\n"); return -1; } /* 创建AAC编码器 */ FFEncoder* audio_encoder = ffencoder_create(0, 0, 0, AUDIO_SAMPLERATE, CODEC_ID_AAC); if (audio_encoder == NULL) { printf("Failed to create AAC encoder\n"); return -1; } /* 打开输出文件 */ FILE* video_output_file = fopen(VIDEO_OUTPUT_FILENAME, "wb"); if (video_output_file == NULL) { printf("Failed to open video output file\n"); return -1; } FILE* audio_output_file = fopen(AUDIO_OUTPUT_FILENAME, "wb"); if (audio_output_file == NULL) { printf("Failed to open audio output file\n"); return -1; } /* 开始音视频采集 */ media_start_capture(); while (1) { /* 采集一帧音视频数据 */ FrameData frame; if (media_capture_frame(&frame) < 0) { printf("Failed to capture frame\n"); break; } /* 编码视频帧 */ if (frame.type == FRAME_TYPE_VIDEO) { AVPacket pkt; if (ffencoder_encode(video_encoder, &frame, &pkt) >= 0) { /* 将H.264码写入文件 */ fwrite(pkt.data, 1, pkt.size, video_output_file); av_packet_unref(&pkt); } } /* 编码音频帧 */ if (frame.type == FRAME_TYPE_AUDIO) { AVPacket pkt; if (ffencoder_encode(audio_encoder, &frame, &pkt) >= 0) { /* 将AAC写入文件 */ fwrite(pkt.data, 1, pkt.size, audio_output_file); av_packet_unref(&pkt); } } } /* 关闭输出文件 */ fclose(video_output_file); fclose(audio_output_file); /* 销毁编码器 */ ffencoder_destroy(video_encoder); ffencoder_destroy(audio_encoder); return 0; } ``` 在这个示例中,我们首先初始化了音视频采集模块,并配置了视频音频的采集参数。然后,我们创建了H.264和AAC编码器,以便将采集到的音视频数据编码为H.264和AAC格式。接着,我们打开了输出文件,并在一个循环中采集音视频数据并进行编码。在编码过程中,我们将H.264码AAC分别写入到输出文件中。最后,我们关闭了输出文件并销毁了编码器。 需要注意的是,示例中使用的编码器和输出文件仅供参考,具体的编码器和输出文件格式可能会因应用场景而有所不同。在实际使用中,需要参考相应的库文档和API参考手册,以获取具体的使用方法和参数信息。同时,在使用RV1109进行音视频开发时,还需要考虑芯片的硬件限制和应用场景的需求,以选择合适的编码器和输出文件格式。
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值