使用FFMPEG分离mp4/flv文件中的264视频和aac音频

这篇具有很好参考价值的文章主要介绍了使用FFMPEG分离mp4/flv文件中的264视频和aac音频。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

 准备

ffmpeg 4.4

一个MP4或flv格式的视频文件

分离流程

大致分为以下几个简单步骤:

1.使用avformat_open_input 函数打开文件并初始化结构AVFormatContext

2.查找是否存在音频和视频信息

3.构建一个h264_mp4toannexb比特流的过滤器,用来给视频avpaket包添加头信息

4.打开2个输出文件(音频, 视频)

5.循环读取视频文件,并将音视频分别写入文件

注意:音频需要手动添加头信息,没有提供aac的adts自动添加的过滤器

ffmpeg flv h264,ffmpeg,ffmpeg,音视频,aac

 源码

#include <stdio.h>
extern "C"
{
#include <libavformat/avformat.h>
}

/* 打印编码器支持该采样率并查找指定采样率下标 */
static int find_sample_rate_index(const AVCodec* codec, int sample_rate)
{
	const int* p = codec->supported_samplerates;
	int sample_rate_index = -1; //支持的分辨率下标
	int count = 0;
	while (*p != 0) {// 0作为退出条件,比如libfdk-aacenc.c的aac_sample_rates
		printf("%s 支持采样率: %dhz  对应下标:%d\n", codec->name, *p, count);

		if (*p == sample_rate)
			sample_rate_index = count;
		p++;
		count++;
	}
	return sample_rate_index;
}


/// <summary>
/// 给aac音频数据添加adts头
/// </summary>
/// <param name="header">adts数组</param>
/// <param name="sample_rate">采样率</param>
/// <param name="channals">通道数</param>
/// <param name="prfile">音频编码器配置文件(FF_PROFILE_AAC_LOW  定义在 avcodec.h)</param>
/// <param name="len">音频包长度</param>
void addHeader(char header[], int sample_rate, int channals, int prfile, int len)
{
	

	uint8_t sampleIndex = 0;    
	switch (sample_rate) {
	case 96000: sampleIndex = 0; break;
	case 88200: sampleIndex = 1; break;
	case 64000: sampleIndex = 2; break;
	case 48000: sampleIndex = 3; break;
	case 44100: sampleIndex = 4; break;
	case 32000: sampleIndex = 5; break;
	case 24000: sampleIndex = 6; break;
	case 22050: sampleIndex = 7; break;
	case 16000: sampleIndex = 8; break;
	case 12000: sampleIndex = 9; break;
	case 11025: sampleIndex = 10; break;
	case 8000: sampleIndex = 11; break;
	case 7350: sampleIndex = 12; break;
	default: sampleIndex = 4; break;
	}

	uint8_t audioType = 2;	//AAC LC

	uint8_t channelConfig = 2;	//双通道

	len += 7;
	//0,1是固定的
	header[0] = (uint8_t)0xff;         //syncword:0xfff                          高8bits
	header[1] = (uint8_t)0xf0;         //syncword:0xfff                          低4bits
	header[1] |= (0 << 3);    //MPEG Version:0 for MPEG-4,1 for MPEG-2  1bit
	header[1] |= (0 << 1);    //Layer:0                                 2bits 
	header[1] |= 1;           //protection absent:1                     1bit
	//根据aac类型,采样率,通道数来配置
	header[2] = (audioType - 1) << 6;            //profile:audio_object_type - 1                      2bits
	header[2] |= (sampleIndex & 0x0f) << 2; //sampling frequency index:sampling_frequency_index  4bits 
	header[2] |= (0 << 1);                             //private bit:0                                      1bit
	header[2] |= (channelConfig & 0x04) >> 2;           //channel configuration:channel_config               高1bit
	//根据通道数+数据长度来配置
	header[3] = (channelConfig & 0x03) << 6;     //channel configuration:channel_config      低2bits
	header[3] |= (0 << 5);                      //original:0                               1bit
	header[3] |= (0 << 4);                      //home:0                                   1bit
	header[3] |= (0 << 3);                      //copyright id bit:0                       1bit  
	header[3] |= (0 << 2);                      //copyright id start:0                     1bit
	header[3] |= ((len & 0x1800) >> 11);           //frame length:value   高2bits
	//根据数据长度来配置
	header[4] = (uint8_t)((len & 0x7f8) >> 3);     //frame length:value    中间8bits
	header[5] = (uint8_t)((len & 0x7) << 5);       //frame length:value    低3bits
	header[5] |= (uint8_t)0x1f;                    //buffer fullness:0x7ff 高5bits
	header[6] = (uint8_t)0xfc;
}


int main() {
	AVFormatContext* ifmt_ctx = NULL;
	AVPacket pkt;
	int ret, i;
	int videoindex = -1, audioindex = -1;
	const char* in_filename = "D:/测试工程/sound/beautlWorld.mp4";
	const char* out_filename_v = "D:/测试工程/sound/ffmpeg_demo.h264";
	const char* out_filename_a = "D:/测试工程/sound/ffmpeg_demo.aac";

	if ((ret = avformat_open_input(&ifmt_ctx, in_filename, 0, 0)) < 0) {
		printf("Could not open input file.");
		return -1;
	}

	if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) {
		printf("Failed to retrieve input stream information");
		return -1;
	}

	videoindex = -1;
	for (i = 0; i < ifmt_ctx->nb_streams; i++) { //nb_streams:视音频流的个数
		if (ifmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
			videoindex = i;
		else if (ifmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
			audioindex = i;
	}

	printf("\nInput Video===========================\n");
	av_dump_format(ifmt_ctx, 0, in_filename, 0);  // 打印信息
	printf("\n======================================\n");

	FILE* fp_audio = fopen(out_filename_a, "wb+");
	FILE* fp_video = fopen(out_filename_v, "wb+");


	AVBSFContext* bsf_ctx = NULL;
	const AVBitStreamFilter* pfilter = av_bsf_get_by_name("h264_mp4toannexb");
	if (pfilter == NULL) {
		printf("Get bsf failed!\n");
	}

	if ((ret = av_bsf_alloc(pfilter, &bsf_ctx)) != 0) {
		printf("Alloc bsf failed!\n");

	}

	ret = avcodec_parameters_copy(bsf_ctx->par_in, ifmt_ctx->streams[videoindex]->codecpar);
	if (ret < 0) {
		printf("Set Codec failed!\n");

	}
	ret = av_bsf_init(bsf_ctx);
	if (ret < 0) {
		printf("Init bsf failed!\n");

	}

	//这里遍历音频编码器打印支持的采样率,并找到当前音频采样率所在的下表,用于后面添加adts头
    //本程序并没有使用,只是测试,如果为了程序健壮性可以采用此方式
	AVCodec* codec = nullptr;
	codec  = avcodec_find_encoder(ifmt_ctx->streams[audioindex]->codecpar->codec_id);
	int sample_rate_index = find_sample_rate_index(codec, ifmt_ctx->streams[audioindex]->codecpar->sample_rate);
	printf("分辨率数组下表:%d\n", sample_rate_index);



	while (av_read_frame(ifmt_ctx, &pkt) >= 0) {
		if (pkt.stream_index == videoindex) {

			av_bsf_send_packet(bsf_ctx, &pkt);

			while (true)
			{
				ret = av_bsf_receive_packet(bsf_ctx, &pkt);
				if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
					break;
				else if (ret < 0) {
					printf("Receive Pkt failed!\n");
					break;
				}

				printf("Write Video Packet. size:%d\tpts:%lld\n", pkt.size, pkt.pts);

				fwrite(pkt.data, 1, pkt.size, fp_video);
			}
			
		}
		else if (pkt.stream_index == audioindex) {
			printf("Write Audio Packet. size:%d\tpts:%lld\n", pkt.size, pkt.pts);
			char adts[7] = { 0 };
			addHeader(adts, ifmt_ctx->streams[audioindex]->codecpar->sample_rate, 
				ifmt_ctx->streams[audioindex]->codecpar->channels, 
				ifmt_ctx->streams[audioindex]->codecpar->profile,
				pkt.size);
			fwrite(adts, 1, 7, fp_audio);
			fwrite(pkt.data, 1, pkt.size, fp_audio);
		}
		av_packet_unref(&pkt);
	}

	av_bsf_free(&bsf_ctx);


	fclose(fp_video);
	fclose(fp_audio);

	avformat_close_input(&ifmt_ctx);
	return 0;


	if (ifmt_ctx)
		avformat_close_input(&ifmt_ctx);
	if (fp_audio)
		fclose(fp_audio);
	if (fp_video)
		fclose(fp_video);
	if (bsf_ctx)
		av_bsf_free(&bsf_ctx);
	return -1;
}

小记

1.av_read_frame 就是读取文件并返回下一帧

2.视频的头信息不在avpacket中需要使用bsf过滤器来添加

3.aac音频头信息需要手动添加文章来源地址https://www.toymoban.com/news/detail-617490.html

到了这里,关于使用FFMPEG分离mp4/flv文件中的264视频和aac音频的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • FFmpeg4入门13:h264编码为mp4

    上一篇将yuv源视频文件编码为 *.h264 的由libx264实现压缩的文件,将源文件从55M编码为620KB,但是h264文件只有视频数据,而且使用范围不太广。那么就需要进一步的封装,在此选用最常用的mp4格式为例。 随便选一个mp4格式文件,用FFmpeg4入门4:解析视频并输出视频信息或者ffp

    2023年04月10日
    浏览(88)
  • 【音视频 ffmpeg 学习】 RTMP推流 mp4文件

    1.RTMP(实时消息传输协议)是Adobe 公司开发的一个基于TCP的应用层协议。 2.RTMP协议中基本的数据单元称为消息(Message)。 3.当RTMP协议在互联网中传输数据的时候,消息会被拆分成更小的单元,称为消息块(Chunk)。 (1). linux 环境准备 安装nginx 和 rtmp模块 下载nginx安装包 下载

    2024年02月03日
    浏览(67)
  • 20231005使用ffmpeg旋转MP4视频

    20231005使用ffmpeg旋转MP4视频 2023/10/5 12:21 百度搜搜:ffmpeg 旋转90度 https://zhuanlan.zhihu.com/p/637790915 【FFmpeg实战】FFMPEG常用命令行 https://blog.csdn.net/weixin_37515325/article/details/127817057 FFMPEG常用命令行 5.视频旋转 顺时针旋转90度:ffmpeg -i test.mp4 -vf \\\"transpose=1\\\" out.mp4//顺时针旋转90° 逆时针

    2024年02月07日
    浏览(49)
  • 用ffmpeg解析mp4文件得到时长、比特率、音视频信息

    以下是使用C++语言调用FFmpeg获取视频流和音频流信息的示例代码: 上述代码通过 AVFormatContext 结构体和FFmpeg库函数 avformat_open_input 、 avformat_find_stream_info 等,获取MP4文件的视频流和音频流信息,并将结果存储到 MediaInfo 类中。在实际应用中,可以将上述代码封装成一个函数,

    2024年02月12日
    浏览(67)
  • 使用ffmpeg将多个TS视频拼接成mp4视频

    点击下面网址下载对应版本安装 https://ffmpeg.org/download.html   下载好之后添加环境变量 添加成功之后在cmd窗口输入ffmpeg,显示如下结果则为成功  合并单个文件或者少量文件时,通过以下命令合并 多个ts视频可以编辑一个txt文档,file.txt 注意:这里必须是单引号,双引号会报错 进入

    2024年02月11日
    浏览(84)
  • Flv格式视频怎么转MP4?视频格式转换方法分享

    FLV格式的视频是一种早期的视频格式,不支持更高的分辨率和比特率,这意味着视频的清晰度和质量受限制,无法很好地保留细节和质量,这种格式的视频已经逐渐被更高质量的视频格式所替代,例如MP4格式,不仅具有很好的兼容性,编辑起来也很方便,下面教大家几种flv转

    2024年02月13日
    浏览(63)
  • C# 使用ffmpeg将图片保存为mp4视频

    使用 FFmpeg 这个强大的多媒体处理工具,可以轻松地将一系列图片转换为一个 MP4 视频文件。以下是一个基本的命令行示例来完成这个任务: 命令参数说明: -framerate 25 :设置输入图像序列的帧率,这里表示每秒25帧。 -i image-%03d.jpg :指定输入文件格式,这里的  %03d  是一个

    2024年04月27日
    浏览(47)
  • OpenCV 报错:FFMPEG: tag 0x34363258/‘X264‘ is not supported with codec id 27 and format ‘mp4 / MP4‘

    首先说一下报错的地方,是在使用VideoWriter保存视频时: 出现如下错误: 经过查找网上资料,发现是cv2.VideoWriter_fourcc()参数存在问题, 解决方法: 将 修改为: 即可完美解决问题。

    2024年02月07日
    浏览(68)
  • Qt/C++音视频开发69-保存监控pcm音频数据到mp4文件/监控录像/录像存储和回放/264/265/aac/pcm等

    用ffmpeg做音视频保存到mp4文件,都会遇到一个问题,尤其是在视频监控行业,就是监控摄像头设置的音频是PCM/G711A/G711U,解码后对应的格式是pcm_s16be/pcm_alaw/pcm_mulaw,将这个原始的音频流保存到mp4文件是会报错的,在调用avformat_write_header写文件头的时候提示(-22) Invalid argument,

    2024年04月11日
    浏览(57)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包