(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 contextAVFormatContext* 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 streamAVStream* videoStream = avformat_new_stream(oc, NULL);//一般数组的第一个都是视频AVStream* audioStream = avformat_new_stream(oc, NULL);///4 copy paraavcodec_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 headint 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)数据的时长,以所属媒体流的时间基准为单位,未知则值为默认值0pos : (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;
}