热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

FFmpeg代码实现最简版本小咖秀

今天代码实现了从两个音视频文件中分别抽取音频、视频数据,并将这两种数据存储在一个新的MP4文件中,文件可以正常播放画面和声音,也就是实现一

今天代码实现了从两个音视频文件中分别抽取音频、视频数据,并将这两种数据存储在一个新的MP4文件中,文件可以正常播放画面和声音,也就是实现一个最简版本的小咖秀。

前面几篇博客已经把需要的知识都讲了一遍,代码流程也基本一致,下面的代码看起来也会非常轻松。

源码实现:

int ret = -1;
int err_code;
char errors[ERROR_STR_SIZE];char *src_file1, *src_file2, *out_file;AVFormatContext *ifmt_ctx1 = NULL;
AVFormatContext *ifmt_ctx2 = NULL;AVFormatContext *ofmt_ctx = NULL;
AVOutputFormat *ofmt = NULL;AVStream *in_stream1 = NULL;
AVStream *in_stream2 = NULL;AVStream *out_stream1 = NULL;
AVStream *out_stream2 = NULL;int audio_stream_index = 0;
int vedio_stream_indes = 0;// 文件最大时长,保证音频和视频数据长度一致
double max_duration = 0;AVPacket pkt;int stream1 = 0, stream2 = 0;av_log_set_level(AV_LOG_DEBUG);src_file1 = argv[1];
src_file2 = argv[2];
out_file = argv[3];//打开两个输入文件
if ((err_code &#61; avformat_open_input(&ifmt_ctx1, src_file1, 0, 0)) <0) {av_strerror(err_code, errors, ERROR_STR_SIZE);av_log(NULL, AV_LOG_ERROR,"Could not open src file, %s, %d(%s)\n",src_file1, err_code, errors);goto END;
}if ((err_code &#61; avformat_open_input(&ifmt_ctx2, src_file2, 0, 0)) <0) {av_strerror(err_code, errors, ERROR_STR_SIZE);av_log(NULL, AV_LOG_ERROR,"Could not open the second src file, %s, %d(%s)\n",src_file2, err_code, errors);goto END;
}//创建输出上下文
if ((err_code &#61; avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, out_file)) <0) {av_strerror(err_code, errors, ERROR_STR_SIZE);av_log(NULL, AV_LOG_ERROR, "Failed to create an context of outfile , %d(%s) \n",err_code, errors);
}ofmt &#61; ofmt_ctx->oformat;// 找到第一个参数里最好的音频流和第二个文件中的视频流下标
audio_stream_index &#61; av_find_best_stream(ifmt_ctx1, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
vedio_stream_indes &#61; av_find_best_stream(ifmt_ctx2, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);// 获取第一个文件中的音频流
in_stream1 &#61; ifmt_ctx1->streams[audio_stream_index];
stream1 &#61; 0;
// 创建音频输出流
out_stream1 &#61; avformat_new_stream(ofmt_ctx, NULL);
if (!out_stream1) {av_log(NULL, AV_LOG_ERROR, "Failed to alloc out stream!\n");goto END;
}
// 拷贝流参数
if ((err_code &#61; avcodec_parameters_copy(out_stream1->codecpar, in_stream1->codecpar)) <0) {av_strerror(err_code, errors, ERROR_STR_SIZE);av_log(NULL, AV_LOG_ERROR,"Failed to copy codec parameter, %d(%s)\n",err_code, errors);
}out_stream1->codecpar->codec_tag &#61; 0;// 获取第二个文件中的视频流
in_stream2 &#61; ifmt_ctx2->streams[vedio_stream_indes];
stream2 &#61; 1;// 创建视频输出流
out_stream2 &#61; avformat_new_stream(ofmt_ctx, NULL);
if (!out_stream2) {av_log(NULL, AV_LOG_ERROR, "Failed to alloc out stream!\n");goto END;
}// 拷贝流参数
if ((err_code &#61; avcodec_parameters_copy(out_stream2->codecpar, in_stream2->codecpar)) <0) {av_strerror(err_code, errors, ERROR_STR_SIZE);av_log(NULL, AV_LOG_ERROR,"Failed to copy codec parameter, %d(%s)\n",err_code, errors);goto END;
}out_stream2->codecpar->codec_tag &#61; 0;av_dump_format(ofmt_ctx, 0, out_file, 1);// 判断两个流的长度&#xff0c;确定最终文件的长度
if (in_stream1->duration * av_q2d(in_stream1->time_base) > in_stream2->duration * av_q2d(in_stream2->time_base)) {max_duration &#61; in_stream2->duration * av_q2d(in_stream2->time_base);
} else {max_duration &#61; in_stream1->duration * av_q2d(in_stream1->time_base);
}//打开输出文件
if (!(ofmt->flags & AVFMT_NOFILE)) {if ((err_code &#61; avio_open(&ofmt_ctx->pb, out_file, AVIO_FLAG_WRITE)) <0) {av_strerror(err_code, errors, ERROR_STR_SIZE);av_log(NULL, AV_LOG_ERROR,"Could not open output file, %s, %d(%s)\n",out_file, err_code, errors);goto END;}
}//写头信息
avformat_write_header(ofmt_ctx, NULL);av_init_packet(&pkt);// 读取音频数据并写入输出文件中
while (av_read_frame(ifmt_ctx1, &pkt) >&#61; 0) {// 如果读取的时间超过了最长时间表示不需要该帧&#xff0c;跳过if (pkt.pts * av_q2d(in_stream1->time_base) > max_duration) {av_packet_unref(&pkt);continue;}// 如果是我们需要的音频流&#xff0c;转换时间基后写入文件if (pkt.stream_index &#61;&#61; audio_stream_index) {pkt.pts &#61; av_rescale_q_rnd(pkt.pts, in_stream1->time_base, out_stream1->time_base,(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));pkt.dts &#61; av_rescale_q_rnd(pkt.dts, in_stream1->time_base, out_stream1->time_base,(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));pkt.duration &#61; av_rescale_q(max_duration, in_stream1->time_base, out_stream1->time_base);pkt.pos &#61; -1;pkt.stream_index &#61; stream1;av_interleaved_write_frame(ofmt_ctx, &pkt);av_packet_unref(&pkt);}
}// 读取视频数据并写入输出文件中
while (av_read_frame(ifmt_ctx2, &pkt) >&#61; 0) {// 如果读取的时间超过了最长时间表示不需要该帧&#xff0c;跳过if (pkt.pts * av_q2d(in_stream2->time_base) > max_duration) {av_packet_unref(&pkt);continue;}// 如果是我们需要的视频流&#xff0c;转换时间基后写入文件if (pkt.stream_index &#61;&#61; vedio_stream_indes) {pkt.pts &#61; av_rescale_q_rnd(pkt.pts, in_stream2->time_base, out_stream2->time_base,(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));pkt.dts &#61; av_rescale_q_rnd(pkt.dts, in_stream2->time_base, out_stream2->time_base,(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));pkt.duration &#61; av_rescale_q(max_duration, in_stream2->time_base, out_stream2->time_base);pkt.pos &#61; -1;pkt.stream_index &#61; stream2;av_interleaved_write_frame(ofmt_ctx, &pkt);av_packet_unref(&pkt);}
}//写尾信息
av_write_trailer(ofmt_ctx)&#xff1b;ret &#61; 0;END:
// 释放内存
if (ifmt_ctx1) {avformat_close_input(&ifmt_ctx1);
}if (ifmt_ctx2) {avformat_close_input(&ifmt_ctx2);
}if (ofmt_ctx) {if (!(ofmt->flags & AVFMT_NOFILE)) {avio_closep(&ofmt_ctx->pb);}avformat_free_context(ofmt_ctx);
}

最终效果如下&#xff0c;从左到右&#xff1a;输入1、输入2、输出文件。输出文件拿到了输入1的音频、输入2的视频信息&#xff0c;并且时长为输入2的时长。

目前只是在做C语言开发&#xff0c;后面会慢慢把重心移到Android平台上&#xff0c;在FFmpeg和Android平台的基础上玩更多有意思的东西。



推荐阅读
  • 在Android平台中,播放音频的采样率通常固定为44.1kHz,而录音的采样率则固定为8kHz。为了确保音频设备的正常工作,底层驱动必须预先设定这些固定的采样率。当上层应用提供的采样率与这些预设值不匹配时,需要通过重采样(resample)技术来调整采样率,以保证音频数据的正确处理和传输。本文将详细探讨FFMpeg在音频处理中的基础理论及重采样技术的应用。 ... [详细]
  • 本文介绍了一种自定义的Android圆形进度条视图,支持在进度条上显示数字,并在圆心位置展示文字内容。通过自定义绘图和组件组合的方式实现,详细展示了自定义View的开发流程和关键技术点。示例代码和效果展示将在文章末尾提供。 ... [详细]
  • 本文介绍了如何利用Shell脚本高效地部署MHA(MySQL High Availability)高可用集群。通过详细的脚本编写和配置示例,展示了自动化部署过程中的关键步骤和注意事项。该方法不仅简化了集群的部署流程,还提高了系统的稳定性和可用性。 ... [详细]
  • 本文介绍了如何利用Struts1框架构建一个简易的四则运算计算器。通过采用DispatchAction来处理不同类型的计算请求,并使用动态Form来优化开发流程,确保代码的简洁性和可维护性。同时,系统提供了用户友好的错误提示,以增强用户体验。 ... [详细]
  • 使用 ListView 浏览安卓系统中的回收站文件 ... [详细]
  • Python 伦理黑客技术:深入探讨后门攻击(第三部分)
    在《Python 伦理黑客技术:深入探讨后门攻击(第三部分)》中,作者详细分析了后门攻击中的Socket问题。由于TCP协议基于流,难以确定消息批次的结束点,这给后门攻击的实现带来了挑战。为了解决这一问题,文章提出了一系列有效的技术方案,包括使用特定的分隔符和长度前缀,以确保数据包的准确传输和解析。这些方法不仅提高了攻击的隐蔽性和可靠性,还为安全研究人员提供了宝贵的参考。 ... [详细]
  • 在Android应用开发中,实现与MySQL数据库的连接是一项重要的技术任务。本文详细介绍了Android连接MySQL数据库的操作流程和技术要点。首先,Android平台提供了SQLiteOpenHelper类作为数据库辅助工具,用于创建或打开数据库。开发者可以通过继承并扩展该类,实现对数据库的初始化和版本管理。此外,文章还探讨了使用第三方库如Retrofit或Volley进行网络请求,以及如何通过JSON格式交换数据,确保与MySQL服务器的高效通信。 ... [详细]
  • 蓝桥杯物联网基础教程:通过GPIO输入控制LED5的点亮与熄灭
    本教程详细介绍了如何利用STM32的GPIO接口通过输入信号控制LED5的点亮与熄灭。内容涵盖GPIO的基本配置、按键检测及LED驱动方法,适合具有STM32基础的读者学习和实践。 ... [详细]
  • 2018年9月21日,Destoon官方发布了安全更新,修复了一个由用户“索马里的海贼”报告的前端GETShell漏洞。该漏洞存在于20180827版本的某CMS中,攻击者可以通过构造特定的HTTP请求,利用该漏洞在服务器上执行任意代码,从而获得对系统的控制权。此次更新建议所有用户尽快升级至最新版本,以确保系统的安全性。 ... [详细]
  • 利用树莓派畅享落网电台音乐体验
    最近重新拾起了闲置已久的树莓派,这台小巧的开发板已经沉寂了半年多。上个月闲暇时间较多,我决定将其重新启用。恰逢落网电台进行了改版,回忆起之前在树莓派论坛上看到有人用它来播放豆瓣音乐,便萌生了同样的想法。通过一番调试,终于实现了在树莓派上流畅播放落网电台音乐的功能,带来了全新的音乐享受体验。 ... [详细]
  • 在探讨如何在Android的TextView中实现多彩文字与多样化字体效果时,本文提供了一种不依赖HTML技术的解决方案。通过使用SpannableString和相关的Span类,开发者可以轻松地为文本添加丰富的样式和颜色,从而提升用户体验。文章详细介绍了实现过程中的关键步骤和技术细节,帮助开发者快速掌握这一技巧。 ... [详细]
  • 本文详细解析了 Android 系统启动过程中的核心文件 `init.c`,探讨了其在系统初始化阶段的关键作用。通过对 `init.c` 的源代码进行深入分析,揭示了其如何管理进程、解析配置文件以及执行系统启动脚本。此外,文章还介绍了 `init` 进程的生命周期及其与内核的交互方式,为开发者提供了深入了解 Android 启动机制的宝贵资料。 ... [详细]
  • Parallels Desktop for Mac 是一款功能强大的虚拟化软件,能够在不重启的情况下实现在同一台电脑上无缝切换和使用 Windows 和 macOS 系统中的各种应用程序。该软件不仅提供了高效稳定的性能,还支持多种高级功能,如拖放文件、共享剪贴板等,极大地提升了用户的生产力和使用体验。 ... [详细]
  • 当使用 `new` 表达式(即通过 `new` 动态创建对象)时,会发生两件事:首先,内存被分配用于存储新对象;其次,该对象的构造函数被调用以初始化对象。为了确保资源管理的一致性和避免内存泄漏,建议在使用 `new` 和 `delete` 时保持形式一致。例如,如果使用 `new[]` 分配数组,则应使用 `delete[]` 来释放内存;同样,如果使用 `new` 分配单个对象,则应使用 `delete` 来释放内存。这种一致性有助于防止常见的编程错误,提高代码的健壮性和可维护性。 ... [详细]
  • 深入探索HTTP协议的学习与实践
    在初次访问某个网站时,由于本地没有缓存,服务器会返回一个200状态码的响应,并在响应头中设置Etag和Last-Modified等缓存控制字段。这些字段用于后续请求时验证资源是否已更新,从而提高页面加载速度和减少带宽消耗。本文将深入探讨HTTP缓存机制及其在实际应用中的优化策略,帮助读者更好地理解和运用HTTP协议。 ... [详细]
author-avatar
G版车臣
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有