FFmpeg 内存H264+PCM发布RTMP

背景

因为项目需要,得从外部获取视频264和音频PCM或者g711编解码数据,然后发布成rtmp出来。目前,网上似乎找不到这样的文章,很多发布RTMP都是用从音视频文件读取后再发布出来,因此记录分享,若有不对的地方,欢迎批评指出。

思路

做这个项目,大体思路是参考FFmpeg的muxing.c。muxing.c主要做的就是输出一个音视频格式,其中它的音频和视频数据都是通过算法生成原始的数据(YUV和PCM),然后再做编码,最后封装成音视频格式。大概的步骤就是:根据输出文件后缀获取音频和视频的编解码ID、填充音视频编码信息、获取音视频原始数据、编解音视频数据、音视频同步操作、音视频封装等。

实施

muxing.c里面的有些视频编码和音频解码我是不需要用到的,所以这部分功能我删减掉了,我这边只要获取到完整的一帧H264视频数据和完整一个待重采样的PCM音频数据(PCM重采样并编码成AAC数据)就可以开始做封装格式的工作。

类的主体内容如下:

typedef struct OutputStream {
	AVStream *st;
	AVCodecContext *enc;

	int64_t next_pts;
	long long samples_count;

	AVFrame *frame;
	AVFrame *tmp_frame;

	struct SwrContext *swr_ctx;
} OutputStream;

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

	int init(const char *filename);
	int writedata(AVMediaType datatype, char *data, int datalen);
private:
	int write_frame(AVFormatContext *fmt_ctx, const AVRational *time_base, AVStream *st, AVPacket *pkt);

	int add_stream(OutputStream *ost, AVCodec **codec, enum AVCodecID codec_id);

	int open_audio(AVCodec *codec, OutputStream *ost, AVDictionary *opt_arg);
	int write_audio_frame(OutputStream *ost, char* data, int datalen);

	int open_video(AVCodec *codec, OutputStream *ost, AVDictionary *opt_arg);
	int write_video_frame(OutputStream *ost, char* data, int datalen);

	void close_stream(OutputStream *ost);

	bool isIdrFrame2(uint8_t *buf, int len);
	bool isIdrFrame1(uint8_t *buf, int size);
private:
	OutputStream video_st, audio_st;
	AVOutputFormat *fmt;
	AVFormatContext *oc;
	AVCodec *audio_codec, *video_codec;
	AVDictionary *opt;

	int have_video, have_audio;
	int ptsInc;

	int iRawLineSize;
	int iRawBuffSize;
	uint8_t *pRawBuff;

	int iConvertLineSize;
	int iConvertBuffSize;
	uint8_t *pConvertBuff;

	char pcmencodebuf[4096];
	int pcmencodesize;
};

接口简单介绍:
init:初始化输出格式信息;
add_stream:添加音视频的编解码参数和通道信息;
open_audio:初始化音频通道信息、打开音频编码器、重采样初始化等;
open_video:初始化视频通道信息;
write_audio_frame:音频重采样、音频编码、编码数据写入等;
write_video_frame:视频编码数据写入;

接口调用

内存H264+PCM发布rtmp

RtmpStream* prtmpstream = NULL;
prtmpstream = new RtmpStream;

//filename可以是后缀名flv文件名也可以是rtmp地址
prtmpstream->init(filename);

//写视频输入的数据是一帧完整的H264数据、写视频是一帧完整的PCM数据
prtmpstream->writedata(AVMEDIA_TYPE_VIDEO, h264buffer, iPsLength);
prtmpstream->writedata(AVMEDIA_TYPE_AUDIO, (char *)audioframe->data[0], audioframe->linesize[0]);

delete prtmpstream;

遇到难点

音频重采样

待重采样的音频数据是要指定固定的采样长度的,不然重采样后再编码的音频播放出来的会是错误的数据。

iRawBuffSize = av_samples_get_buffer_size(&iRawLineSize, c->channels, nb_samples, AV_SAMPLE_FMT_S16, 0);
pRawBuff = (uint8_t *)av_malloc(iRawBuffSize);

ost->tmp_frame = av_frame_alloc();
ost->tmp_frame->nb_samples = nb_samples;
ost->tmp_frame->format = AV_SAMPLE_FMT_S16;
ost->tmp_frame->channels = c->channels;

ret = avcodec_fill_audio_frame(ost->tmp_frame, c->channels, AV_SAMPLE_FMT_S16, (const uint8_t*)pRawBuff, iRawBuffSize, 0);
if (ret<0)
{
	printf("Could not fill input audio frame\n");
	return -1;
}

iRawBuffSize 这个就是送入重采样的PCM数据长度。

下载

源码下载:https://download.csdn.net/download/qq_22633333/11617399

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 14
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值