ffmpeg为mkv封装格式的音视频文件添加内挂字幕(代码片段)

tusong86 tusong86     2023-04-05     422

关键词:

现在好莱坞的电影,都是全球看,一个地区的人看电影时,电影屏幕上应该展示对应的本地区语言字幕。故电影画面在不同的地区,需要配置不同的语言字幕。故视频画面里面的字幕应该可以拆出来,不能像老版三国演义,每到经典处,展示出文字,如下所示:

这种文字是直接嵌入到视频画面,无法拆出来,这种字幕也叫内嵌字幕。

本文要讲的是内挂字幕,字幕在视频文件里面,但是是独立的通道,可以独立拆出来。当然,还有一种外挂字幕,是在视频文件外面,播放器播放时,可以选择本地的字幕文件。

就封装格式而言,目前mkv对字幕支持的最好,读者可以先准备下字幕文件,字幕文件,读者可以网上下载现有的,也可以自己制作,本文准备的字幕文件ts.ass的内容如下:

[Script Info]
Title: Untitled
ScriptType: v4.00+
PlayResX:1280
PlayResY:720
WrapStyle: 0
ScaledBorderAndShadow: yes

[V4+ Styles]
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
Style: Default,Arial,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,0,0,0,0,100,100,0,0,1,2,2,2,10,10,10,1

[Events]
Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
Dialogue: 2,0:00:00.22,0:00:31.93,Default,,0,0,0,,就算身处 流逝的时光里
Dialogue: 0,0:00:32.02,0:00:36.18,Default,,0,0,0,,也只有倦怠 在原地打转不停
Dialogue: 0,0:00:36.19,0:00:38.85,Default,,0,0,0,,从我身边 渐行渐远的心
Dialogue: 0,0:00:39.03,0:00:43.15,Default,,0,0,0,,再也模糊不清 你明白吗
Dialogue: 0,0:00:43.20,0:00:45.67,Default,,0,0,0,,我的身体 已经动弹不得
Dialogue: 0,0:00:45.79,0:00:50.16,Default,,0,0,0,,在时间的狭缝里 随波逐流
Dialogue: 0,0:00:50.17,0:00:53.26,Default,,0,0,0,,周围的一切 都与我无关
Dialogue: 0,0:00:53.39,0:00:57.07,Default,,0,0,0,,我就是我 仅·此·而·已
Dialogue: 0,0:00:57.18,0:01:00.04,Default,,0,0,0,,我在做梦吗?什么都没在看
Dialogue: 0,0:01:00.18,0:01:03.56,Default,,0,0,0,,出口也是枉然 自怜自艾的废话
Dialogue: 0,0:01:03.66,0:01:07.08,Default,,0,0,0,,悲伤什么的 只会徒增疲倦啊
Dialogue: 0,0:01:07.21,0:01:10.52,Default,,0,0,0,,干脆就这样 在麻木中度日吧
Dialogue: 0,0:01:10.62,0:01:13.95,Default,,0,0,0,,就算被灌以 喧嚣的闲言碎语
Dialogue: 0,0:01:14.09,0:01:17.45,Default,,0,0,0,,我的心也已经 不再起一丝涟漪
Dialogue: 0,0:01:17.56,0:01:21.03,Default,,0,0,0,,如果我能够 驱使自己的话
Dialogue: 0,0:01:21.13,0:01:24.39,Default,,0,0,0,,就让这一切 被黑暗所吞没吧
Dialogue: 0,0:01:24.50,0:01:28.06,Default,,0,0,0,,这样的我 还有未来可言吗
Dialogue: 0,0:01:28.19,0:01:31.46,Default,,0,0,0,,这种世界 允许我的存在吗
Dialogue: 0,0:01:31.56,0:01:34.85,Default,,0,0,0,,此刻感到窒息吗?此刻觉得悲伤吗
Dialogue: 0,0:01:34.98,0:01:38.45,Default,,0,0,0,,就连自己的事 也根本搞不懂啊
Dialogue: 0,0:01:38.55,0:01:41.94,Default,,0,0,0,,就算走下去 也只是徒增疲倦
Dialogue: 0,0:01:42.06,0:01:45.32,Default,,0,0,0,,对他人的一切 完全无法理解
Dialogue: 0,0:01:45.42,0:01:48.64,Default,,0,0,0,,这样的我 如果还能改变
Dialogue: 0,0:01:48.78,0:01:52.14,Default,,0,0,0,,还能改变的话 可以化为空白吗
Dialogue: 0,0:02:06.79,0:02:09.33,Default,,0,0,0,,就算身处 流逝的时光里
Dialogue: 0,0:02:09.48,0:02:13.64,Default,,0,0,0,,也只有倦怠 在原地打转不停
Dialogue: 0,0:02:13.77,0:02:16.24,Default,,0,0,0,,从我身边 渐行渐远的心
Dialogue: 0,0:02:16.37,0:02:20.54,Default,,0,0,0,,再也模糊不清 你明白吗
Dialogue: 0,0:02:20.67,0:02:23.26,Default,,0,0,0,,我的身体 已经动弹不得
Dialogue: 0,0:02:23.36,0:02:27.67,Default,,0,0,0,,在时间的狭缝里 随波逐流
Dialogue: 0,0:02:27.68,0:02:31.19,Default,,0,0,0,,周围的一切 都与我无关
Dialogue: 0,0:02:31.28,0:02:34.31,Default,,0,0,0,,我就是我 仅·此·而·已
Dialogue: 0,0:02:34.49,0:02:37.50,Default,,0,0,0,,我在做梦吗?什么都没在看
Dialogue: 0,0:02:37.62,0:02:40.93,Default,,0,0,0,,出口也是枉然 自怜自艾的废话
Dialogue: 0,0:02:41.03,0:02:44.30,Default,,0,0,0,,悲伤什么的 只会徒增疲倦啊
Dialogue: 0,0:02:44.43,0:02:47.91,Default,,0,0,0,,干脆就这样 在麻木中度日吧
Dialogue: 0,0:02:47.99,0:02:51.61,Default,,0,0,0,,就算被灌以 喧嚣的闲言碎语
Dialogue: 0,0:02:51.72,0:02:54.73,Default,,0,0,0,,我的心也已经 不再起一丝涟漪
Dialogue: 0,0:02:54.82,0:02:58.30,Default,,0,0,0,,如果我能够 驱使自己的话
Dialogue: 0,0:02:58.39,0:03:02.04,Default,,0,0,0,,就让这一切 被黑暗所吞没吧
Dialogue: 0,0:03:02.05,0:03:05.39,Default,,0,0,0,,如果任我驱使 驱使自己的话
Dialogue: 0,0:03:05.47,0:03:08.92,Default,,0,0,0,,一切都会毁灭 一切都会毁灭啊
Dialogue: 0,0:03:09.03,0:03:12.36,Default,,0,0,0,,被悲伤笼罩 被悲伤笼罩的话
Dialogue: 0,0:03:12.47,0:03:15.74,Default,,0,0,0,,我的心还能够 化为空白吗
Dialogue: 0,0:03:15.85,0:03:19.25,Default,,0,0,0,,不论你的存在 还是我的存在
Dialogue: 0,0:03:19.35,0:03:22.67,Default,,0,0,0,,这一切的真实 我都一无所知
Dialogue: 0,0:03:22.79,0:03:26.18,Default,,0,0,0,,如果在此睁开 这沉重的双眼
Dialogue: 0,0:03:26.36,0:03:29.88,Default,,0,0,0,,一切都会毁灭 被黑暗所吞没


读者可以清晰的看到,哪段时间至哪段时间,界面需要展示的文字,比如最后一个Dialogue显示在03:26.36到0:03:29.88这段时间,界面应该展示一切都会毁灭 被黑暗所吞没。

可以通过如下的ffmpeg命令降此字幕内挂到视频文件中

ffmpeg -i TAEYEON-Weekend.mkv -i ts.ass -c copy output.mkv

下面用ffmpeg代码的方式展示如何实现。
首先,需要说明的是,字幕跟音频,视频一样,有自己的通道,有自己的time_base,其读取方法也是av_read_frame。这点跟内嵌字幕不一样,在一个视频中,添加内嵌文字,可以通过滤镜drawtext实现,有解码,滤镜运算,编码过程,很费时,内挂不一样,没有这三个费时的计算,故往视频文件中添加内挂字幕很快。

其次,本人通过两个队列m_vecMediaPacket和m_vecAssPacket来存储读取的packet,然后在一个线程里面按照写入时间顺序分别写入m_vecMediaPacket和m_vecAssPacket的数据。

std::deque<AVPacket *> m_vecMediaPacket;
std::deque<AVPacket *> m_vecAssPacket;

此处,本人在av_read_frame,得到AVPacket后,没有直接调用av_interleaved_write_frame写文件,最主要的原因是av_interleaved_write_frame里面会对AVPacket的时间(相对各自的AVStream)进行排序,若视频文件比较大,则可能里面需要分配的空间也越来越大,最终由于内存不足导致崩溃。
故本人将读取的音视频packet和字幕packet分别存入队列,然后按照音视频播放同步的原理,调用av_write_frame依次写入m_vecMediaPacket和m_vecAssPacket里面的内容。也就是音视频的packet和字幕的packet,由自己编码判断谁先写(代码中av_compare_ts部分),而不是交由av_interleaved_write_frame处理。

再次,本人讲解下代码的大致结构:
1.用avformat_open_input分别打开媒体文件和字幕文件
2.avformat_alloc_output_context2构建输出文件context后,用avformat_new_stream分别往里面添加媒体流和字幕流,代码如下:

int iStreamNum = m_pFormatCtx_MediaFile->nb_streams;
for (int i = 0; i < iStreamNum; i++)

	AVCodec* pCodecEncode_Media = (AVCodec *)avcodec_find_encoder(m_pFormatCtx_MediaFile->streams[i]->codecpar->codec_id);
	AVStream *pMediaStream = avformat_new_stream(m_pFormatCtx_Out, pCodecEncode_Media);
	if (!pCodecEncode_Media)
	
		break;
	
	avcodec_parameters_copy(pMediaStream->codecpar, m_pFormatCtx_MediaFile->streams[i]->codecpar);
	pMediaStream->codecpar->codec_tag = 0;



	
	AVCodec* pCodecEncode_Ass = (AVCodec *)avcodec_find_encoder(m_pFormatCtx_AssFile->streams[0]->codecpar->codec_id);
	AVStream *pAssStream = avformat_new_stream(m_pFormatCtx_Out, pCodecEncode_Ass);
	if (!pAssStream)
	
		break;
	
	avcodec_parameters_copy(pAssStream->codecpar, m_pFormatCtx_AssFile->streams[0]->codecpar);
	pAssStream->codecpar->codec_tag = 0;

3.创建三个线程,如下所示:

m_hMediaFileReadThread = CreateThread(NULL, 0, MediaFileReadProc, this, 0, NULL);
m_hAssFileReadThread = CreateThread(NULL, 0, AssFileReadProc, this, 0, NULL);
m_hWriteThread = CreateThread(NULL, 0, WriteProc, this, 0, NULL);

前两个线程分别读取媒体流和字幕流,然后塞入队列,第三个线程读取两个队列中的数据,然后按照时间顺序写入packet。
这里说明下,对于字幕流而言,av_read_frame,本人调用到了48次,这48次,其实也是上面的ass文件中,Dialogue节点的数量。

最后,是代码,文件结构如下:

其中FfmpegMkvTest.cpp内容如下:

#include <iostream>
#include "FfmpegAddAss.h"

int main()

	CFfmpegAddAss cFfmpegAddAss;
	std::string strMediaFile = "D:/learn/ffmpeg/FfmpegConvert/x64/Release/TAEYEON-Weekend.mkv";
	std::string strAssFile = "D:/learn/ffmpeg/FfmpegConvert/x64/Release/ts.ass";

	std::string strOutFile = "D:/learn/ffmpeg/FfmpegConvert/x64/Release/TAEYEON-Weekend_ass.mkv";
	cFfmpegAddAss.StartAddAss(strMediaFile, strAssFile, strOutFile);
	cFfmpegAddAss.WaitFinish();
	return 0;

其中WaitFinish函数在文件处理结束后,会返回。

FfmpegAddAss.h的内容如下:

#pragma once

#include <string>
#include <Windows.h>
#include <deque>

#define MAX_PACKET_NUM 200

#ifdef	__cplusplus
extern "C"

#endif
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "libswresample/swresample.h"
#include "libavdevice/avdevice.h"
#include "libavutil/audio_fifo.h"
#include "libavutil/avutil.h"
#include "libavutil/fifo.h"
#include "libavutil/frame.h"
#include "libavutil/imgutils.h"

#include "libavfilter/avfilter.h"
#include "libavfilter/buffersink.h"
#include "libavfilter/buffersrc.h"


#ifdef __cplusplus
;
#endif

class CFfmpegAddAss

public:
	CFfmpegAddAss();
	~CFfmpegAddAss();
public:
	int StartAddAss(std::string strMediaFile, std::string strAssFile, std::string strOutFile);
	void WaitFinish();
private:
	int OpenMediaFile(std::string strMediaFile);
	int OpenAssFile(std::string strAssFile);
	int OpenOutFile(std::string strOutFile);
private:
	static DWORD WINAPI MediaFileReadProc(LPVOID lpParam);
	void MediaFileRead();

	static DWORD WINAPI AssFileReadProc(LPVOID lpParam);
	void AssFileRead();

	static DWORD WINAPI WriteProc(LPVOID lpParam);
	void Write();
private:
	AVFormatContext *m_pFormatCtx_MediaFile = NULL;
	AVFormatContext *m_pFormatCtx_AssFile = NULL;
	AVFormatContext *m_pFormatCtx_Out = NULL;
	int m_iAssStreamIndex = -1;
	HANDLE m_hMediaFileReadThread = NULL;
	HANDLE m_hAssFileReadThread = NULL;
	HANDLE m_hWriteThread = NULL;
	std::deque<AVPacket *> m_vecMediaPacket;
	std::deque<AVPacket *> m_vecAssPacket;
	CRITICAL_SECTION m_csMediaSection;
	CRITICAL_SECTION m_csAssSection;
	bool m_bStart = false;
;


FfmpegAddAss.cpp内容如下:

#include "FfmpegAddAss.h"


#ifdef	__cplusplus
extern "C"

#endif

#pragma comment(lib, "avcodec.lib")
#pragma comment(lib, "avformat.lib")
#pragma comment(lib, "avutil.lib")
#pragma comment(lib, "avdevice.lib")
#pragma comment(lib, "avfilter.lib")
#pragma comment(lib, "postproc.lib")
#pragma comment(lib, "swresample.lib")
#pragma comment(lib, "swscale.lib")


#ifdef __cplusplus
;
#endif

CFfmpegAddAss::CFfmpegAddAss()

	InitializeCriticalSection(&m_csMediaSection);
	InitializeCriticalSection(&m_csAssSection);


CFfmpegAddAss::~CFfmpegAddAss()

	DeleteCriticalSection(&m_csMediaSection);
	DeleteCriticalSection(&m_csAssSection);


int CFfmpegAddAss::StartAddAss(std::string strMediaFile, std::string strAssFile, std::string strOutFile)

	int ret = 0;
	do
	
		ret = OpenMediaFile(strMediaFile);
		if (ret < 0)
		
			break;
		
		ret = OpenAssFile(strAssFile);
		if (ret < 0)
		
			break;
		
		ret = OpenOutFile(strOutFile);
		if (ret < 0)
		
			break;
		
		m_bStart = true;
		m_hMediaFileReadThread = CreateThread(NULL, 0, MediaFileReadProc, this, 0, NULL);
		m_hAssFileReadThread = CreateThread(NULL, 0, AssFileReadProc, this, 0, NULL);
		m_hWriteThread = CreateThread(NULL, 0, WriteProc, this, 0, NULL);

	 while (0);
	
	return ret;


void CFfmpegAddAss::WaitFinish()

	DWORD dw = 0;
	for (int i = 0; i < 10000; i++)
	
		if (m_hMediaFileReadThread == NULL && m_hAssFileReadThread == NULL)
		
			break;
		
		if (m_hMediaFileReadThread != NULL)
		
			dw = WaitForSingleObject(m_hMediaFileReadThread, 1000);
			if (dw == WAIT_OBJECT_0)
			
				CloseHandle(m_hMediaFileReadThread);
				m_hMediaFileReadThread = NULL;
			
		
		
		if (m_hAssFileReadThread != NULL)
		
			dw = WaitForSingleObject(m_hAssFileReadThread, 1000);
			if (dw == WAIT_OBJECT_0)
			
				CloseHandle(m_hAssFileReadThread);
				m_hAssFileReadThread = NULL;
			
		
	

	while (m_vecMediaPacket.size() > 0 && m_vecAssPacket.size() > 0)
	
		Sleep(1000);
	
	Sleep(1000);
	m_bStart = false;

	WaitForSingleObject(m_hWriteThread, INFINITE);
	CloseHandle(m_hWriteThread);
	m_hWriteThread = NULL;


int CFfmpegAddAss::OpenMediaFile(std::string strMediaFile)

	int ret = -1;

	do
	
		if ((ret = avformat_open_input(&m_pFormatCtx_MediaFile, strMediaFile.c_str(), 0, 0)) < 0) 
			break;
		
		if ((ret = avformat_find_stream_info(m_pFormatCtx_MediaFile, 0)) < 0) 
			break;
		

		ret = 0;
	 while (0);


	return ret;


int CFfmpegAddAss::OpenAssFile(std::string strAssFile)

	int ret = -1;

	do
	
		if ((ret = avformat_open_input(&m_pFormatCtx_AssFile, strAssFile.c_str(), 0, 0)) < 0) 
			break;
		
		if ((ret = avformat_find_stream_info(m_pFormatCtx_AssFile, 0)) < 0) 
			break;
		

		ret = 0;
	 while (0);


	return ret;



int CFfmpegAddAss::OpenOutFile(std::string strOutFile)

	int iRet = -1;

	do
	
		avformat_alloc_output_context2(&m_pFormatCtx_Out, NULL, NULL, strOutFile.c_str());

		int iStreamNum = m_pFormatCtx_MediaFile->nb_streams;
		for (int i = 0; i < iStreamNum; i++)
		
			AVCodec* pCodecEncode_Media = (AVCodec *)avcodec_find_encoder(m_pFormatCtx_MediaFile->streams[i]->codecpar->codec_id);
			AVStream *pMediaStream = avformat_new_stream(m_pFormatCtx_Out, pCodecEncode_Media);
			if (!pCodecEncode_Media)
			
				break;
			
			avcodec_parameters_copy(pMediaStream->codecpar, m_pFormatCtx_MediaFile->streams[i]->codecpar);
			pMediaStream->codecpar->codec_tag = 0;
		

		
			
			AVCodec* pCodecEncode_Ass = (AVCodec *)avcodec_find_encoder(m_pFormatCtx_AssFile->streams[0]->codecpar->codec_id);
			AVStream *pAssStream = avformat_new_stream(m_pFormatCtx_Out, pCodecEncode_Ass);
			if (!pAssStream)
			
				break;
			
			avcodec_parameters_copy(pAssStream->codecpar, m_pFormatCtx_AssFile->streams[0]->codecpar);
			pAssStream->codecpar->codec_tag = 0;
		

		if (!(m_pFormatCtx_Out->oformat->flags & AVFMT_NOFILE))
		
			if (avio_open(&m_pFormatCtx_Out->pb, strOutFile.c_str(), AVIO_FLAG_WRITE) < 0)
			
				break;
			
		



		if (avformat_write_header(m_pFormatCtx_Out, NULL) < 0)
		
			break;
		
		m_iAssStreamIndex = iStreamNum;
		iRet = 0;
	 while (0);


	if (iRet != 0)
	
		if (m_pFormatCtx_Out != NULL)
		
			avformat_free_context(m_pFormatCtx_Out);
			m_pFormatCtx_Out = NULL;
		
	

	return iRet;


DWORD WINAPI CFfmpegAddAss::MediaFileReadProc(LPVOID lpParam)

	CFfmpegAddAss *pFfmpegAddAss = (CFfmpegAddAss *)lpParam;
	if (pFfmpegAddAss != NULL)
	
		pFfmpegAddAss->MediaFileRead();
	
	return 0;


void CFfmpegAddAss::MediaFileRead()

	AVPacket packet =  0 ;
	int ret = 视频剪辑

1、为视频添加字幕:(1)将MKV视频和外挂字幕软封装在一起:使用MKVToolnix工具进行封装,变成内挂字幕,播放时一些支持的播放器就会自动加载内挂字幕,如若对字幕不满意仍然可以更换字幕。但使用视频剪辑软件(爱剪辑、... 查看详情

ffmpeg音视频解码

...下载的视频文件如MP4,MKV、FLV等都属于封装格式,就是把音视频数据按照相应的规范,打包成一个文本文件。我们可以使用MediaInfo这个工具查看媒体文件的相关信息。所以当我们播放一个媒体文件时,通常需要经过以下几个步骤... 查看详情

这个是啥回事,我应该怎么弄啊!

...,而是Matroska的一种媒体文件,Matroska是一种新的多媒体封装格式,也称多媒体容器(MultimediaContainer)。它可将多种不同编码的视频及16条以上不同格式的音频和不同语言的字幕流封装到一个MatroskaMedia文件当中。MKV最大的特点就是... 查看详情

基于ffmpeg的封装格式转换器

 简介本文介绍一个基于FFMPEG的封装格式转换器。所谓的封装格式转换,就是在AVI,FLV,MKV,MP4这些格式之间转换(对应.avi,.flv,.mkv,.mp4文件)。需要注意的是,本程序并不进行视音频的... 查看详情

ffmpeg基础:获取音视频的各种编码参数(代码片段)

...获取视频编码参数获取音频编码参数上一篇文章中介绍了音视频的各种编码参数的概念,这里介绍一下如何通过ffmpeg库获取一个视频文件的各种音视频编码参数。在对视频文件进行处理和转码的时候这些参数很重要。获取视... 查看详情

ffmpeg[30]-使用ffmpeg命令生成常见的音频和视频格式的文件

目录问题解决一、视频格式1)mp42)avi3)mkv4)mov 查看详情

ffmpeg命令行工具ffmpeg

...d到文件所在地文件夹也是可以的,直接使用文件名1.列出ffmpeg支持的所有格式:2.剪切一段媒体文件,可以使音频或者视频文件:3.将一个媒体文件切割成多个媒体文件:4.提取一个视频文件中的音频文件:5.提取一个视频文件中... 查看详情

muxerdemuxermuxer是什么?视频封装解封装(逆封装)

muxer是指合并文件,即将视频文件、音频文件和字幕文件合并为某一个视频格式。比如把rmvb格式的视频,mp3格式的音频文件以及srt格式的字幕文件,合并成为一个新的mp4或者mkv格式的文件。demuxer是muxer的逆过程,... 查看详情

ffmpeg播放视频文件流程

一、FFmpeg解码播放主要流程,如图1-1所示:使用播放一个媒体文件时,通常需要经过以下几个步骤:                              图1-1  FFmpeg播放视频文件流程1、解封装(Demuxing):就是将输入... 查看详情

mkv与rmvb,avi,mp4等有啥区别似乎同样的电影mkv格式的是rmvb格式的3到4倍大小

...:mkv不等同于音频或视频编码格式,它只是为这些进行过音视频编码的数据提供了一个封装的格式,简单的说就是指定音视频数据在文件中如何排列放置。MKV最大的特点就是能容纳多种不同类型编码的视频、音频及字幕流,俗称... 查看详情

百度云是如何支持播放mkv和rmvb格式视频的

...v”格式电影,你可以使用MyMPC来播放这种格式的电影MKV是封装RMVB是压缩格式MKV中可以装AVI或者RMVB,所以MKV的质量关键看它封装了什么格式的视频在里面,如果是RMVB的,那么就和RMVB一样,如果是AVI,那当然要清晰的多!什么播... 查看详情

把h264文件快速包装成mp4格式

mkv里封装的.h264文件提取出来后,不能直接导入到premiere等视频编辑软件里,需要转换成mp4文件。这里介绍如何把封装在mkv里面的.h264视频文件转换为mp4格式。(只有视频,不含音频)此种方法速度快,比用格式转换软件mkv转mp4快... 查看详情

ffmpeg视频转换问题

...用户界面,非常易于使用,参数设置十分简单参考技术Affmpeg转码命令很多,根据你要输入的视频的格式和输出的格式来定了,一个例子:ffmpeg-iamite.ts-fmpegts-acodeclibfaac-ar48000-ab64k-s1280x720-vcodec 查看详情

ffmpeg 添加视频标题/名称作为字幕轨道

】ffmpeg添加视频标题/名称作为字幕轨道【英文标题】:ffmpegaddvideotitle/nameassubtitletrack【发布时间】:2020-02-0514:16:14【问题描述】:有没有一种简单的方法可以使用ffmpeg将视频(mp4、mkv等)的标题添加为自定义字幕轨道(在整个... 查看详情

使用ffmpeg实现对h264视频解码--(实现了一个易于使用的c++封装库)(代码片段)

H264是当今流行的视频压缩格式;ffmpeg是一个开源库,实现了对h264视频文件的解压缩。为了降低使用ffmpeg的复杂性,尽量隐藏实现细节,我写了一个封装库。c#也可以很方便的使用此库。解压后的数据可以为yuv格式,也可以为rgb... 查看详情

使用 ffmpeg 将 mkv 转换为 mp4 有时会丢失视频

】使用ffmpeg将mkv转换为mp4有时会丢失视频【英文标题】:Convertingmkvtomp4withffmpegsometimeslosesvideo【发布时间】:2019-12-0920:54:32【问题描述】:如何创建一个尽可能通用的命令行来将mkv转换为mp4?我修复了一个问题,有时我会丢失音... 查看详情

转音视频封装格式编码格式知识

 常见的AVI、RMVB、MKV、ASF、WMV、MP4、3GP、FLV等文件其实只能算是一种封装标准。一个完整的视频文件是由音频和视频2部分组成的。H264、Xvid等就是视频编码格式,MP3、AAC等就是音频编码格式。例如:将一个Xvid视频编码文件和... 查看详情

ffmpegsdk使用5调用ffmpegsdk解析封装格式的视频为音频流和视频流(代码片段)

...是大家最为熟悉的,因为它直接体现在了我们使用的音视频文件扩展名上,比较常见的有mp4、avi、mkv、flv等等。在进行音频和视频封装时,我们将实际操作一系列音频或视频流数 查看详情