最近下载了10多个G的学习视频,结果一播放,发现声音和画面不同步,原本以为大脑能自动调整画面和和画面,勉强能看下去,结果一分钟不到崩溃了,因为声音比画面快了20秒😓;
原本想删了算了,但是下载了几个礼拜才下好,所以只能想想办法
方案一:众所周知,声音的传播速度是 340m/s,找跟长的线,只要把音响放的足够远,理论上是能达到声音和画面同步;果然是学好数理化,走遍天下都不怕啊;实际体验效果我就不尝试了,哈哈🤣
方案二:如果是电脑,同时打开两个视频播放器,一个只听声音,一个静音只看画面;如果是手机,没办法同时打开两个视频播放器,那就只能两个手机了;亲测可用😎
方案三:之前接触过ffmpeg,专门处理音视频流的,查了下果然可以,相关命令如下:
// 音频相对于视频后移20秒(00:00:20),如果前移就是(-00:00:20)
ffmpeg -y -itsoffset 00:00:20 -i 源视频.mp4 -i 源视频.mp4 -map 0:a -map 1:v -vcodec copy -acodec copy -f mp4 -threads 2 -v warning 调整后的视频.mp4
// 用得到的参数:
// -y 可覆盖,如果文件已存在强制替换;
// -itsoffset offset 设置以秒为基准的时间偏移,该选项影响所有后面的输入文件。该偏移被加到输入文件的时戳,定义一个正偏移意味着相应的流被延迟了offset秒。 [-]hh:mm:ss[.xxx]的格式也支持
// -f fmt 强迫采用格式fmt
// -v 调试信息级别(quiet、panic、fatal、error、warning、info、verbose、debug)
// 选择媒体流,AVI,mkv,mp4等,可以包含不同种类的多个流
每个视频都手动敲一行命令太麻烦了,写代码批量生成岂不快哉;废话不多说,直接上代码:
#include <string>
#include <iostream>
#include <vector>
#include <thread>
#include <windows.h>
#include <string.h>
#include <io.h>
#include <direct.h>
#include <shlwapi.h>
#pragma comment(lib,"shlwapi.lib")
using namespace std;
vector<string> g_vecVideoPaths;
#define ERR_NO_FIND -1
int FindFile(const char* pszPath)
int iRet = 0;
char szFindPath[MAX_PATH] = { 0 };
DWORD dwFileAttributes;
string strFileName;
WIN32_FIND_DATA wfd;
sprintf(szFindPath, "%s*.*", pszPath);
HANDLE hFindFile = ::FindFirstFile(szFindPath, &wfd);
if (hFindFile == INVALID_HANDLE_VALUE)
return ERR_NO_FIND;
strFileName = wfd.cFileName;
while (strFileName.size() > 0)
if (strFileName != "." && strFileName != "..")
dwFileAttributes = wfd.dwFileAttributes;
if (dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY)
char szSubFindPath[MAX_PATH] = { 0 };
sprintf(szSubFindPath, "%s%s\\", pszPath, strFileName.c_str());
iRet = FindFile(szSubFindPath);
if (iRet != 0)
break;
else if (dwFileAttributes == FILE_ATTRIBUTE_ARCHIVE)
const char* pExtension = PathFindExtension(strFileName.c_str());
if(pExtension != nullptr &&
(stricmp(pExtension, ".mp4") == 0 || stricmp(pExtension, ".mkv") == 0 || stricmp(pExtension, ".rmvb") == 0))
g_vecVideoPaths.push_back(string(pszPath) + strFileName);
if (!::FindNextFile(hFindFile, &wfd))
break;
strFileName = wfd.cFileName;
::FindClose(hFindFile);
return iRet;
void GenerateVideo(const char* pPath)
if (g_vecVideoPaths.size() == 0)
cout << "查找视频资源失败" << endl;
return;
cout << "--------------------开始调整-------------------------" << endl;
int iAdjustTime = 0;
cout << "请输入要调整的时间(单位:秒),音频后移为正数,前移为负数:";
cin >> iAdjustTime;
char szSavePath[MAX_PATH] = { 0 };
char szFileName[MAX_PATH] = { 0 };
char szSaveFileName[MAX_PATH] = { 0 };
char szCommand[1024] = { 0 };
char szAdjustTime[32] = {0};
char* pPrefix = "";
if (iAdjustTime < 0)
pPrefix = "-";
iAdjustTime = -iAdjustTime;
int iHour = iAdjustTime / 3600;
int iMinute = (iAdjustTime % 3600) / 60;
int iSecond = iAdjustTime % 60;
sprintf(szAdjustTime, "%s%02d:%02d:%02d", pPrefix, iHour, iMinute, iSecond);
auto funAdjust = [](string strCommand)
system(strCommand.c_str());
for (int i = 0; i < g_vecVideoPaths.size(); i++)
if (g_vecVideoPaths[i].size() == 0)
continue;
memset(szSavePath, 0, sizeof(szSavePath));
strcpy(szSavePath, g_vecVideoPaths[i].c_str());
const char* pFileName = PathFindFileName(szSavePath);
memset(szFileName, 0, sizeof(szFileName));
strcpy(szFileName, pFileName);
PathRemoveFileSpec(szSavePath);
strcat(szSavePath, "\\output");
if (_access(szSavePath, 0) == -1)
_mkdir(szSavePath);
sprintf(szSaveFileName, "%s\\%s", szSavePath, szFileName);
sprintf(szCommand, "%sffmpeg.exe -y -itsoffset %s -i %s -i %s -map 0:a -map 1:v -vcodec copy -acodec copy -f mp4 -threads 2 -v warning %s",
pPath, szAdjustTime, g_vecVideoPaths[i].c_str(), g_vecVideoPaths[i].c_str(), szSaveFileName);
cout << szCommand << endl;
std::thread t(funAdjust, szCommand);
t.join();
cout << i << " --- " << "输出:" << szSaveFileName << endl;
int main()
char szModuleFileName[MAX_PATH] = { 0 };
::GetModuleFileName(NULL, szModuleFileName, MAX_PATH);
char szFindPath[MAX_PATH] = { 0 };
strcpy(szFindPath, szModuleFileName);
char *pPos = strrchr(szFindPath, '\\');
if (pPos == NULL)
return -1;
pPos[1] = '\0';
FindFile(szFindPath);
GenerateVideo(szFindPath);
system("pause");
return 0;
最终生成的程序需要下载的请点击:c++声音和画面同步,免积分下载
之前的3篇博客,实现了视频音频解码读帧,并同步播放,这篇讲将实现视频进度条的功能,实现拖动播放。还是使用教程【3】的代码,需要前3篇教程的,请点击以下链接:
基于FFmpeg的视频播放器开发系列教程(三)
基于FFmpeg的视频播放器开发系列教程(二)
基于FFmpeg的视频播放器开发系列教程(一)
先在Qt Des...
[导读]使用FFMPEG转码一年半的时间,遇到了各种情况的音视频不同步,下面我们就来根据问题出现的原因,对所遇到的音视频不同步做一个分类。使用FFMPEG转码一年半的时间,遇到了各种情况的音视频不同步,下面我们就来根据问题出现的原因,对所遇到的音视频不同步做一个分类。1. 源本身音视频不同步且无法播放这种情况极为罕见,在A客户东方卫视频道转码时遇到过。表现为输出的音视频严重不匹配,录制下来的视频源...
FFmpeg 开发系列连载:
FFmpeg 开发(01):FFmpeg 编译和集成
FFmpeg 开发(02):FFmpeg + ANativeWindow 实现视频解码播放
FFmpeg 开发(03):FFmpeg + OpenSLES 实现音频解码播放
FFmpeg 开发(04):FFmpeg + OpenGLES 实现音频可视化播放
FFmpeg 开发(05):FFmpeg + OpenGLES 实现视频解码播放和视频滤镜
前文中,我们基于 FFmpeg 利用 ..
vs版本:vs2017
ffmpeg版本:
built with gcc 8.1.0 (x86_64-win32-seh-rev0, Built by MinGW-W64 project)
configuration: --arch=x86_64 --disable-debug --enable-shared --disable-static --e
音视频同步简介
从前面的学习可以知道,在一个视频文件中,音频和视频都是单独以一条流的形式存在,互不干扰。那么在播放时根据视频的帧率(Frame Rate)和音频的采样率(Sample Rate)通过简单的计算得到其在某一Frame(Sample)的播放时间分别播放,**理论**上应该是同步的。但是由于机器运行速度,解码效率等等因素影响,很有可能出现音频和视频不同步,例如出现视频中人在说话,却只能看到人物嘴动却没有声音,非常影响用户观看体验。
如何做到音视频同步?要知道音视频同步是一个动态的过程,同步是暂
在用解码器解码音频数据得到PCM音频数据块之后,可以在将数据送给声卡播放之前调节其音量大小,具体的实现函数如下:
void RaiseVolume(char* buf, UINT32 size, UINT32 uRepeat, double vol)//buf为需要调节音量的音频数据块首地址指针,size为长度,uRepeat为重复次数,通常设为1,vol为增益倍数,可以小于1
if (!
C 语言的内存管理,分成两部分。一部分是系统管理的,另一部分是用户手动管理的。
系统管理的内存,主要是函数内部的变量(局部变量)。这部分变量在函数运行时进入内存,函数运行结束后自动从内存卸载。这些变量存放的区域称为”栈“(stack),”栈“所在的内存是系统自动管理的。
用户手动管理的内存,主要是程序运行的整个过程中都存在的变量(全局变量),这些变量需要用户手动从内存释放。如果使用后忘记释放,它就一直占用内存,直到程序退出,这种情况称为”内存泄漏“(memory leak)。这些变量所在的内存称为”堆
我们基于 FFmpeg 利用 OpenGL ES 和 OpenSL ES 分别实现了对解码后视频和音频的渲染,本文将实现播放器的最后一个重要功能:音视频同步。老人们经常说,播放器对音频和视频的播放没有绝对的静态的同步,只有相对的动态的同步,实际上音视频同步就是一个“你追我赶”的过程。音视频的同步方式有 3 种,即:音视频分别向系统时钟同步、音频向视频同步及视频向音频同步。
第一个视频无声,合并之后整个视频无声
例如上面是我用图片合成的视频,就是没有音频的视频。只要没有音频的视频放在最前面,那么整个视频都会没有声音,ffmpeg默认以第一个视频为标准。
解决方法:给第一个视频添加音频
ffmpeg -i 1.mp4 -i a.mp3 -vcodec copy -acodec copy 1.mp4
ps:如果是图片合成的视频,上面命令可能会报错,建议重新合成视频,此时一定得加上音频
ffmpeg -r 15 -f image2 -loop 1 -i 图片.png -i
HDMI是很常见的的输入接口,英文全称是High Definition Multimedia Interface,中文即高清多媒体界面,它是一种数字化影像和声音发送接口,可以发送未压缩的音频及视频信号。HDMI可以同时发送音频和视频信号,由于音频和视频信号采用同一条线材,大大简化系统线路的安装难度,其接口呈倒梯形,较偏平。如下图:HDMI的接口分成A、B、C、D4种类型。A类(Type A)是最常...
ffmpeg是世界上应用广的开源视频处理框架,在各个平台(windows,linux,嵌入式、Android、IOS)被广泛应用,可以说是做视频相关项目技能qt是目前跨平台项目界面开发的第一选择,本课程基于这两种框架在加上VC++,给大家讲解延时如何开发出一个视频播放器,各个模块如何结合,如何考虑性能问题,如何设计封装类,如何处理各种异常情况。