需求:

将一首歌mp3格式,和一段无声音录屏mp4格式,合成到一起,使播放视频时能听到这首歌。

实现原理:

打开mp3音频,解析出输入音频流,再打开mp4视频,解析出输入视频流。

然后打开输出环境,创建2个输出流,分别对应音频输入流和视频输入流。

最后循环交替从音频流和视频流读取AVPacket,依次写入输出环境。

使用ffmpeg命令实现音视频混合很简单:

ffmpeg -i xxx1.mp3 -i xxx2.mp4 out.mp4

要点:

1 AVPacket::stream_index

将AVPacket写入输出环境时,音频和视频的stream_index不能相等,如果音频的stream_index等于0,那么视频的stream_index需要等于1,可以手动改。出现这种情况的原因是输入的xxx1.mp3可能包含2个流,一个是音频,另一个是视频,音频流索引是0,视频流索引是1。这里的视频实际上是播放音乐时显示的一张图片。输入的xxx2.mp4至少包含2个流,一个是音频,另一个是视频,而这里视频流索引是0,音频流索引是1。画个图:

xxx1.mp3

- stream0(audio)

- stream1(video)

xxx2.mp4

- stream0(video)

- stream1(audio)

出现这种情况,从xxx1.mp3解析出来的AVPacket和xxx2.mp4解析出来的AVPacket的stream_index都为0,如果不改直接写到输出环境,ffmpeg就会报错。

2 void av_packet_rescale_ts(AVPacket *pkt, AVRational tb_src, AVRational tb_dst);

* Convert valid timing fields (timestamps / durations) in a packet from one
 * timebase to another. Timestamps with unknown values (AV_NOPTS_VALUE) will be
 * ignored.

将从输入流解析出的AVPacket的跟时间相关字段,从当前的输入流时基对应的值转为输出流时基对应的值。音频和视频都是用这个函数。这样合成后的音频和视频就能有序播放。

3 别犯低级错误,比如成员变量pkg与pkg2混淆导致出问题。

附上调试学习研究用的代码

文件名xxx.c(cpp会编不过)

包含目录,ffmpeg头文件所在的目录

C:\work\env\msys2\usr\local\include;

包含库目录,ffmpeg静态库所在的目录

C:\work\env\msys2\usr\local\lib;

依赖的静态库

libavcodec.a

libavdevice.a

libavfilter.a

libavformat.a

libavutil.a

libswresample.a

libswscale.a

SDL2.lib

SDL2main.lib

mfuuid.lib

ole32.lib

strmiids.lib

user32.lib

psapi.lib

uuid.lib

oleaut32.lib

shlwapi.lib

gdi32.lib

vfw32.lib

secur32.lib

ws2_32.lib

bcrypt.lib

// 需求:将一首歌mp3格式,和一段无声音录屏mp4格式,合成到一起,使播放视频时能听到这首歌。//#include <file.h>#include "libavformat/avformat.h"
#include "libavutil/dict.h"
#include "libavutil/opt.h"
#include "libavutil/timestamp.h"
#include "libswscale/swscale.h"
#include "libswresample/swresample.h"
#include "libavutil/imgutils.h"
#include "libavcodec/avcodec.h"static void log_packet(const AVFormatContext* fmt_ctx, const AVPacket* pkt, const char* tag)
{AVRational* time_base = &fmt_ctx->streams[pkt->stream_index]->time_base;printf("%s: pts:%s pts_time:%s dts:%s dts_time:%s duration:%s duration_time:%s stream_index:%d\n",tag,av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, time_base),av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, time_base),av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, time_base),pkt->stream_index);
}int main()
{int ret = 0;// 打开音频流avformat_network_init();AVFormatContext* ifmt_ctx = NULL;const char* inputUrl = "jietuo.mp3";ret = avformat_open_input(&ifmt_ctx, inputUrl, NULL, NULL);if (ret != 0){printf("Couldn't open input stream.\n");return -1;}if (avformat_find_stream_info(ifmt_ctx, NULL) < 0){printf("Couldn't find stream information.\n");return -1;}av_dump_format(ifmt_ctx, 0, inputUrl, 0);int audio_index = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);AVStream* st = ifmt_ctx->streams[audio_index];const AVCodec* codec = NULL;codec = avcodec_find_decoder(st->codecpar->codec_id);if (!codec){fprintf(stderr, "Codec not found\n");exit(1);}AVCodecContext* codec_ctx = NULL;codec_ctx = avcodec_alloc_context3(codec);if (!codec_ctx){exit(1);}avcodec_parameters_to_context(codec_ctx, ifmt_ctx->streams[audio_index]->codecpar);if ((ret = avcodec_open2(codec_ctx, codec, NULL) < 0)){return -1;}AVPacket* pkt = av_packet_alloc();// 打开视频流AVFormatContext* ifmt_ctx2 = NULL;const char* inputUrl2 = "luping.mp4";ret = avformat_open_input(&ifmt_ctx2, inputUrl2, NULL, NULL);if (ret != 0){printf("Couldn't open input stream %s.\n", inputUrl2);return -1;}if (avformat_find_stream_info(ifmt_ctx2, NULL) < 0){printf("Couldn't find stream information.\n");return -1;}av_dump_format(ifmt_ctx2, 0, inputUrl2, 0);int video_index = av_find_best_stream(ifmt_ctx2, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);AVStream* st2 = ifmt_ctx2->streams[video_index];const AVCodec* codec2 = NULL;codec2 = avcodec_find_decoder(st2->codecpar->codec_id);if (!codec2){fprintf(stderr, "Codec not found\n");exit(1);}AVCodecContext* codec_ctx2 = NULL;codec_ctx2 = avcodec_alloc_context3(codec2);if (!codec_ctx2){exit(1);}avcodec_parameters_to_context(codec_ctx2, ifmt_ctx2->streams[video_index]->codecpar);if ((ret = avcodec_open2(codec_ctx2, codec2, NULL) < 0)){return -1;}AVPacket* pkt2 = av_packet_alloc();// 打开输出流const char* outputUrl = "out.mp4";AVFormatContext* ofmt_ctx = NULL;avformat_alloc_output_context2(&ofmt_ctx, NULL, "mpegts", outputUrl);if (!ofmt_ctx) {printf("Could not create output context\n");return -1;}const AVOutputFormat* ofmt = ofmt_ctx->oformat;{//创建输出音频流AVStream* out = avformat_new_stream(ofmt_ctx, NULL);if (!out){return -1;}//复制配置信息AVCodecParameters* codecpar = ifmt_ctx->streams[audio_index]->codecpar;avcodec_parameters_copy(out->codecpar, codecpar);out->codecpar->codec_tag = 0;}{//创建输出视频流AVStream* out = avformat_new_stream(ofmt_ctx, NULL);if (!out){return -1;}//复制配置信息AVCodecParameters* codecpar = ifmt_ctx2->streams[video_index]->codecpar;avcodec_parameters_copy(out->codecpar, codecpar);out->codecpar->codec_tag = 0;}av_dump_format(ofmt_ctx, 0, outputUrl, 1);//Open output URLif (!(ofmt->flags & AVFMT_NOFILE)) {ret = avio_open(&ofmt_ctx->pb, outputUrl, AVIO_FLAG_WRITE);if (ret < 0) {printf("Could not open output URL '%s'", outputUrl);return -1;}}//Write file headerret = avformat_write_header(ofmt_ctx, NULL);if (ret < 0) {printf("Error occurred when opening output URL\n");return -1;}int duration_audio = 0;int duration_video = 0;// 音视频合成while (1){//if (duration_audio < duration_video){AVStream* in_stream, * out_stream;ret = av_read_frame(ifmt_ctx, pkt);if (ret < 0)break;if (pkt->stream_index == audio_index){in_stream = ifmt_ctx->streams[pkt->stream_index];out_stream = ofmt_ctx->streams[0];log_packet(ifmt_ctx, pkt, "in");/* copy packet */av_packet_rescale_ts(pkt, in_stream->time_base, out_stream->time_base);pkt->pos = -1;log_packet(ofmt_ctx, pkt, "out");duration_audio += pkt->duration;ret = av_interleaved_write_frame(ofmt_ctx, pkt);/* pkt is now blank (av_interleaved_write_frame() takes ownership of* its contents and resets pkt), so that no unreferencing is necessary.* This would be different if one used av_write_frame(). */if (ret < 0) {fprintf(stderr, "Error muxing packet\n");break;}}else{av_packet_unref(pkt);}}//else{AVStream* in_stream, * out_stream;ret = av_read_frame(ifmt_ctx2, pkt2);if (ret < 0)break;if (pkt2->stream_index == video_index){in_stream = ifmt_ctx2->streams[pkt2->stream_index];pkt2->stream_index = 1;out_stream = ofmt_ctx->streams[1];log_packet(ifmt_ctx2, pkt2, "in");/* copy packet */av_packet_rescale_ts(pkt2, in_stream->time_base, out_stream->time_base);pkt2->pos = -1;log_packet(ofmt_ctx, pkt2, "out");duration_video += pkt2->duration;ret = av_interleaved_write_frame(ofmt_ctx, pkt2);/* pkt is now blank (av_interleaved_write_frame() takes ownership of* its contents and resets pkt), so that no unreferencing is necessary.* This would be different if one used av_write_frame(). */if (ret < 0) {fprintf(stderr, "Error muxing packet\n");break;}}else{av_packet_unref(pkt2);}}/*if (av_read_frame(ifmt_ctx2, pkt2) >= 0){if (pkt2->stream_index == video_index){int video = av_find_best_stream(ofmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);av_packet_rescale_ts(pkt2, st2->time_base, ofmt_ctx->streams[video]->time_base);av_interleaved_write_frame(ofmt_ctx, pkt2);}}else{break;}if (av_read_frame(ifmt_ctx, pkt) >= 0){if (pkt->stream_index == audio_index){int audio = av_find_best_stream(ofmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);av_interleaved_write_frame(ofmt_ctx, pkt);}}*/}av_write_trailer(ofmt_ctx);return 0;
}

ffmpeg api实现将音视频混合相关推荐

  1. ffmpeg混音以及音视频混合

    Duration = MAX(input a, v) 0. 前言 本文包括以下内容: (1)混音:多个音频混合 采用amerge, amix对多个音频进行混音(而非拼接) (2)音视频混合--muxi ...

  2. 【ffmpeg for wince】音视频编解码多平台移植(for window/wince)

    from: http://www.cnblogs.com/windwithlife/archive/2009/05/31/1492728.html 终于完成了了第二个Client side原型(for ...

  3. 一步步教ffmpeg的C语言音视频编程

    欢迎访问我的博客原文:https://lightfish.cn/2018-12-20-ffmpeg-primer 前言 本文以 ffmpeg 工具,讲述如何认识音视频编程,你可以了解到常见视频格式的大 ...

  4. ffmpeg命令录制windows音视频

    欢迎转载请注明出处:海漩涡 http://blog.csdn.net/tanhuifang520                 ffmpeg命令录制windows音视频 一.下载ffmpeg 存放在 ...

  5. FFmpeg入门详解--音视频原理及应用:梅会东:清华大学出版社

    大家好,我的第一本书正式出版了,可以在京东各大店铺抢购哦. <FFmpeg入门详解--音视频原理及应用:梅会东:清华大学出版社> 京东自营链接:https://item.jd.com/13 ...

  6. 短视频app源码开发,音视频混合的实现

    在短视频app源码开发中,音视频的混合是对音视频数据进行处理时,非常重要的一个环节,只有做好了音视频混合,才能录制更好的短视频内容. //音视频合成 func videoAudioMerge() {/ ...

  7. ffmpeg前景_5G时代音视频开发前景怎么样?音视频开发需要掌握哪些技术?

    前言 从历史来看,2G打开了了移动互联网天下,3G带来了即时通信,诞生了QQ 微信等巨头,4G 带来了短视频兴起.字节跳动等公司崛起.2 3 4G的出现促成了移动互联网10年繁荣.而5G的出现,也会促 ...

  8. ffmpeg api的应用——提取视频图片

    这些年来,"短视频"吸引了无数网民的注意.相对于丰富有趣的内容,我们码农可能更关心其底层技术实现.本系列文章将结合ffmpeg,讲解几则视频处理案例.(转载请指明出于breakso ...

  9. ffmpeg rtsp转hls_Qt音视频开发24-ffmpeg音视频同步

    ## 一.前言 用ffmpeg来做音视频同步,个人认为这个是ffmpeg基础处理中最难的一个,无数人就卡在这里,怎么也不准,本人也是尝试过网上各种demo,基本上都是渣渣,要么仅仅支持极其少量的视频文 ...

最新文章

  1. 通过PXE网络安装ESXI6
  2. springboot的jsp应该放在哪_web项目jsp放在哪里 Spring Boot 静态资源处理(4)
  3. Could not get unknown property 'ANDROID_BUILD_SDK_VERSION'
  4. SCN试验之二 checkpoin scn 与数据库scn的关系
  5. 无向图的直径以及树的直径
  6. 地球空间与数字测绘知识总结
  7. Centos系列 Curl error (37): Couldn‘t read a file:// file for file:///etc/pki/rpm-gpg/RPM-GPG-KEY-XXXX
  8. MySQL不区分大小写(Linux与WINDOWS)
  9. pgpool-II的master-slave模式的分析
  10. CentOS 7 (RHEL 7)服务管理命令的变化
  11. RFC 791翻译(IP的主要内容)
  12. WPS下 宏使用js编写及一些脚本
  13. listlength函数头文件_length函数
  14. 自动驾驶技术基础——惯导
  15. Android Studio:Type mismatch: inferred type is Int but Unit was expected
  16. 前端性能优化--测试工具
  17. 数据之道读书笔记-03差异化的企业数据分类管理框架
  18. Ubuntu虚拟机没有网络图标或者无法获取IP地址
  19. 如何解决EDIUS无法打开文件的问题
  20. 作文 深海机器人_作文机器人(共5篇)

热门文章

  1. Activiti设置流程发起用户信息【包括获取发起人信息代码】
  2. java电话号码开头_Java正则表达式验证电话号码
  3. 简陋中带点动画的太极图
  4. Canny算子的理解
  5. ImmunoChemistry丨ICT艾美捷MicroTiter平板设计说明书
  6. 那些过目不忘的 H5 页面
  7. 指纹很安全?发个红包就把你打回原形
  8. 英睿达硬盘测试软件,【英睿达 MX300 750GB SATA3 固态硬盘外观测试】软件|界面|容量|传输_摘要频道_什么值得买...
  9. 云南地震灾区最急需防雨保暖物资 食品药品不足
  10. html微信播放器,原生js 编写的微信播放器插件(仿微信公众号播放器组件)