音视频(关于视频的封装,由mp4->mov)

(20条消息) FFmpeg + Visual studio 开发环境搭建_HW140701的博客-CSDN博客

1.封装格式:AVI,MP4,ASF

AVI:压缩标准可以任意选

FLV,ts:直播等使用的流媒体

mp4:既是封装又是压缩

#pragma comment(lib,"avcodec.lib")
#pragma comment(lib,"avutil.lib")

int main(int argc, char *argv[])
{
	char infile[] = "test.mp4";//要转的文件
	char outfile[] = "test.mov";//目标文件
	av_register_all();//注册了很多东西
	/*AVFormatContext **ps整个封装格式上下文
		{
			    AVIOContext *pb;IO上下文,通过他可以进行写入
				AVStream **streams;视频音频字幕流,存放了所有的流的信息,一般这个数组的第一个是视频,第二个是音频

		}
	const char * url音视频文件地址
	AVInputFormat *fmt音视频格式,此格式可以传NULL,由url决定
	AVDictionary **options音视频格式的参数
	*/
	AVFormatContext* ic = NULL;
	/**
 * 打开输入流并读取标头。编解码器未打开。
 * 流必须使用 avformat_close_input() 关闭。
 *
 * @param ps 指向用户提供的 AVFormatContext 的指针(由 avformat_alloc_context 分配)。
 * 可能是指向 NULL 的指针,在这种情况下,AVFormatContext 由此分配
 * 函数并写入 PS。
 * 请注意,用户提供的 AVFormatContext 将在失败时释放。
 * @param要打开的流的网址网址。
 * @param fmt 如果非 NULL,则此参数强制使用特定的输入格式。
 * 否则会自动检测格式。
 * @param选项 一个充满AVFormatContext和demuxer-private选项的字典。
 * 返回时,此参数将被销毁并替换为包含
 * 未找到的选项。可能为空。
 *
 * 成功时为 @return 0,失败时为 AVERROR 为负值。
 *
 * @note 如果要使用自定义 IO,请预分配格式上下文并设置其 pb 字段。
 */
	avformat_open_input(&ic, infile, 0, 0);//后两个参数可根据音频文件的后缀自动检测
	if (!ic)
	{
		cout << "avformat_open_input failed!" << endl;
		getchar();
	}

	///2 create output context
	AVFormatContext* oc = NULL;
	/**
 * 为输出格式分配 AVFormatContext。
 * avformat_free_context() 可用于释放上下文和
 * 其中框架分配的所有内容。
 *
 * @param *ctx 设置为创建的格式上下文,或在
 * 故障案例
 * @param用于分配上下文的 oformat 格式,如果为 NULL
 * 改用format_name和文件名
 * @param format_name用于分配
 * 上下文,如果使用 NULL 文件名代替
 * @param文件名 用于分配
 * 上下文,可能是空的
 * @return >= 0 如果成功,则为负 AVERROR 代码
 *失败
 */
	avformat_alloc_output_context2(&oc, NULL, NULL, outfile);
	if (!oc)
	{
		cerr << "avformat_alloc_output_context2 " << outfile << " failed!" << endl;
		getchar();
		return -1;
	}

	///3 add the stream
	AVStream* videoStream = avformat_new_stream(oc, NULL);//一般数组的第一个都是视频
	AVStream* audioStream = avformat_new_stream(oc, NULL);

	///4 copy para
	avcodec_parameters_copy(videoStream->codecpar, ic->streams[0]->codecpar);
	avcodec_parameters_copy(audioStream->codecpar, ic->streams[1]->codecpar);

	videoStream->codecpar->codec_tag = 0;//有关编解码器的其他信息,我们此处不进行使用
	audioStream->codecpar->codec_tag = 0;

	av_dump_format(ic, 0, infile, 0);//打印输入文件的信息
	cout << "================================================" << endl;
	av_dump_format(oc, 0, outfile, 1);//打印输出文件的信息


	///5 open out file io,write head
	int ret = avio_open(&oc->pb, outfile, AVIO_FLAG_WRITE);
	if (ret < 0)
	{
		cerr << "avio open failed!" << endl;
		getchar();
		return -1;
	}
	/**
 * 分配流私有数据并将流标头写入
 * 输出媒体文件。
 *
 * @param 的媒体文件句柄,必须使用 avformat_alloc_context() 分配。
 *其oformat字段必须设置为所需的输出格式;
 * 其 pb 字段必须设置为已打开的 AVIOContext。
 * @param选项 一个充满 AVFormatContext 和 muxer-private 选项的 AVDictionary。
 * 返回时,此参数将被销毁并替换为包含
 * 未找到的选项。可能为空。
 *
 * 如果编解码器尚未在avformat_init中完全初始化,则@return AVSTREAM_INIT_IN_WRITE_HEADER成功,
 * 如果编解码器已在 avformat_init 中完全初始化,则AVSTREAM_INIT_IN_INIT_OUTPUT成功,
 * 失败时的负面 AVERROR。
 *
 * @see av_opt_find、av_dict_set、avio_open、av_oformat_next、avformat_init_output。
 */
	ret = avformat_write_header(oc, NULL);
	if (ret < 0)
	{
		cerr << "avformat_write_header failed!" << endl;
		getchar();
	}
	AVPacket pkt;
	for (;;)
	{
		int re = av_read_frame(ic, &pkt);//此处注意,因为帧长不一定,所以每次循环需要把之前的数据清理掉
		if (re < 0)
			break;

/**
	 * 以 AVStream->time_base 为单位的演示时间戳;时间
	 * 解压缩的数据包将呈现给用户。
	 * 如果未存储在文件中,则可以AV_NOPTS_VALUE。
	 * pts 必须大于或等于 dts,因为演示之前不能发生
	 *解压缩,除非有人想查看十六进制转储。某些格式滥用
	 * 术语 DTS 和 PTS/CTS 的含义不同。这样的时间戳
	 * 在存储在 AVPacket 中之前,必须转换为真正的 pts/dts。
	AVPacket:
		pts: (int64_t)显示时间,结合AVStream->time_base转换成时间戳
		dts : (int64_t)解码时间,结合AVStream->time_base转换成时间戳
		size : (int)data的大小
		stream_index : (int)packet在stream的index位置

		flags : (int)标示,结合AV_PKT_FLAG使用,其中最低为1表示该数据是一个关键帧。
		#define AV_PKT_FLAG_KEY    0x0001 //关键帧
		#define AV_PKT_FLAG_CORRUPT 0x0002 //损坏的数据
		#define AV_PKT_FLAG_DISCARD  0x0004 /丢弃的数据

		side_data_elems : (int)边缘数据元数个数
		duration : (int64_t)数据的时长,以所属媒体流的时间基准为单位,未知则值为默认值0
		pos : (int64_t )数据在流媒体中的位置,未知则值为默认值 - 1
*/
		pkt.pts = av_rescale_q_rnd(pkt.pts,
			ic->streams[pkt.stream_index]->time_base,
			oc->streams[pkt.stream_index]->time_base,
			(AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)
		);
		pkt.dts = av_rescale_q_rnd(pkt.dts,
			ic->streams[pkt.stream_index]->time_base,
			oc->streams[pkt.stream_index]->time_base,
			(AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)
		);
		pkt.pos = -1;
		pkt.duration = av_rescale_q_rnd(pkt.duration,
			ic->streams[pkt.stream_index]->time_base,
			oc->streams[pkt.stream_index]->time_base,
			(AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)
		);

		av_write_frame(oc, &pkt);
		av_packet_unref(&pkt);
		cout << ".";
	}

	av_write_trailer(oc);//加一个尾字段,类似于记录前面每一帧的索引和总的时长。
	avio_close(oc->pb);
	cout << "================end================" << endl;




	getchar();
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对不起,我之前的回答有误。麦克风和摄像头采集语音和视频画面到在电视墙上播放的过程与声音采集 -> 数字化处理 -> 视频采集 -> 数字化处理 -> 视音频同步 -> 数据编码 -> 文件格式封装 -> 媒体文件生成的过程类似,但有些区别。 1. 麦克风和摄像头采集语音和视频画面:麦克风和摄像头采集到的语音和视频画面会被转换成模拟信号,然后经过模拟信号放大和处理后,转换成数字信号。 2. 数字化处理:数字信号经过采样、量化和编码等数字化处理,转换成计算机可处理的数字信号。 3. 视音频同步:将数字化后的语音和视频画面进行同步,确保声音和画面的时间轴一致。 4. 数据编码:将数字化后的声音和视频画面进行编码,将其转换为可以被计算机识别和处理的格式,如H.264、AAC等。 5. 文件格式封装:将编码后的声音和视频画面数据按照特定的格式进行封装,如MP4、AVI等格式,生成最终的媒体文件。 6. 信号传输:采集到的数字信号通过信号传输设备,如放大器、分配器等设备进行信号放大和分配,并通过数据线连接到电视墙。 7. 信号处理:传输到电视墙的信号需要进行处理,如降噪、增强、格式转换等处理,确保信号的质量。 8. 信号切换:电视墙可以通过控制面板对采集到的语音和视频画面进行切换和调度,根据需要将不同的信号输出到屏幕上。 9. 电视墙显示:电视墙将处理和切换后的信号转化成画面并在屏幕上显示。 整个过程可以用以下流程图表示: 麦克风和摄像头采集语音和视频画面 -> 模拟信号放大和处理 -> 数字化处理 -> 视音频同步 -> 数据编码 -> 文件格式封装 -> 信号传输 -> 信号处理 -> 信号切换 -> 电视墙显示

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值