ffmpeg入门

ffmpeg入——安装

Fmpeg地址

FFmpeg源码地址:https://github.com/FFmpeg/FFmpeg

FFmpeg可执行文件地址:https://ffmpeg.org/download.html

Windows平台

Windows平台下载解压后如图所示(文件名称以-share结尾的是开发库)

FFmpeg库介绍

◆ ffmpeg.exe:用于音视频转码, 也可以从url/现场音频/视频源抓取输入源。

◆ ffplay.exe:一个非常简单和可移植的媒体播放器,使用FFmpeg库和SDL库。

◆ ffprobe.exe:查看多媒体文件的信息

将FFmpeg可执行文件加入系统环境变量,如下图所示:

Linux

ffmpeg官方 GitHub - FFmpeg/FFmpeg: Mirror of https://git.ffmpeg.org/ffmpeg.git

下载压缩包 或者 直接clone

  1. 直接clone:git clone https://github.com/FFmpeg/FFmpeg.git
  2. 下载完成,执行./configure

        如果出现了错误 nasm/yasm not found or too old. Use --disable-x86asm for a crippled build.

        这是因为 FFMPEG为了提高编译速度,使用了汇编指令,如MMX和SSE等。如果系统中没有yasm指令的话,就会该错误。

        1)下载:wget http://www.tortall.net/projects/yasm/releases/yasm-1.3.0.tar.gz

        2)解压:tar zxvf yasm-1.3.0.tar.gz

        3)切换路径: cd yasm-1.3.0

        4)执行配置: ./configure

        5)编译:make

        6)安装:make install

3.make && sudo make install 

测试代码:

#include<stdio.h>
#include<libavutil/log.h>


int main()
{
	av_log_set_level(AV_LOG_DEBUG);            //设置日志等级
	av_log(NULL, AV_LOG_INFO, "Hello~~~\n");       // INFO等级,输出hello

	return 0;
}

 编译链接: gcc -o ff_log ff_log.c -lavutil
        或者 gcc -o ff_log ff_log.c `pkg-config --cflags --libs libavutil`

(“pkg-config工具:1)会检查库的版本号。如果所需要的库的版本不满足要求,它会打印出错误信息,避免链接错误版本的库文件;2)会获得编译预处理参数,如宏定义,头文件的位置。3)还会获得链接参数,如库及依赖的其它库的位置,文件名及其它一些连接参数

        选项--cflags 它是用来指定程序在编译时所需要头文件所在的目录, 选项 --libs则是指定程序在链接时所需要的动态链接库的目录。

ffmpeg——log日志系统

log日志位于libavutil模块,log level的声明位于log.h

日志级别:

// 静默模式,不打印日志
#define AV_LOG_QUIET    -8
 
// 立即崩溃,退出程序
#define AV_LOG_PANIC     0
 
// 严重出错,无法修复
#define AV_LOG_FATAL     8
 
// 程序出错
#define AV_LOG_ERROR    16
 
// 警告
#define AV_LOG_WARNING  24
 
// 信息
#define AV_LOG_INFO     32
 
// 详细信息
#define AV_LOG_VERBOSE  40
 
// 调试日志
#define AV_LOG_DEBUG    48
 
// 跟踪日志
#define AV_LOG_TRACE    56

设置日志等级的方法set_log_level()位于log.c,其中av_log_level是个静态全局变量,具体如下

static int av_log_level = AV_LOG_INFO;
 
void av_log_set_level(int level)
{
    av_log_level = level;
}

常用的打印日志方法av_log(),声明位于log.h:

/** 
 * 发送特定消息到小于等于当前等级的日志,默认全部发送到stderr
 *
 * @param avcl  指向任意结构体的指针,结构体第一个变量为AVClass或NULL
 * @param level 日志等级
 * @param fmt   字符串格式
 */
void av_log(void *avcl, int level, const char *fmt, ...) av_printf_format(3, 4);

ffmpeg——文件的删除与重命名 

  • avpriv_io_delete() //删除
  • avpriv_io_move()  //重命名

编译链接: gcc xxx.c -o xxx   -lavformat -lavutil

#include <libavformat/avformat.h>
 
int main(int argc,char *argv[])
{
        int ret;
        set_av_log_level(AV_LOG_DEBUG);
        ret = avpriv_io_move("111.txt","222.txt");
        if(ret < 0)
        {
                av_log(NULL,AV_LOG_ERROR,"Failed to move file:%s\n","111.txt");
                return -1;
        }
 
        

        ret = avpriv_io_delete("./mytestfile.txt");
        if(ret < 0)
        {
                av_log(NULL,AV_LOG_ERROR,"Failed to delete file:%s\n","mytestfile.txt");
                return -1;
        }
 
        av_log(NULL,AV_LOG_DEBUG,"Success to delete file:%s\n","mytestfile.txt");
 
        return 0;
}

ffmpeg——目录操作

重要结构体:

        AVIODirContext  操作目录的上下文(记录avio_open_dir打开目录信息)

        AVIODirEntry  目录项。用于存放文件名,文件大小等信息

操作目录API:

  • avio_open_dir()
  • avio_read_dir()//读取目录中每一个文件的属性
  • avio_close_dir()

编译链接: gcc xxx.c -o xxx   -lavformat -lavutil

// 实现简单的ls命令

#include <libavutil/log.h>
#include <libavformat/avformat.h>
 
int main(int argc,char* argv[])
{
        int ret;
        AVIODirContext *ctx = NULL;
        AVIODirEntry *entry = NULL;
        av_log_set_level(AV_LOG_INFO);
 
        ret = avio_open_dir(&ctx,"./",NULL);
        if(ret < 0){
                av_log(NULL,AV_LOG_ERROR,"Cant open dir:%s\n",av_err2str(ret));
                return -1;
        }
 
        while(1){
                ret = avio_read_dir(ctx,&entry);//malloc entry
                if(ret < 0){
                        av_log(NULL,AV_LOG_ERROR,"Cant read dir:%s\n",av_err2str(ret));
                        avio_close_dir(&ctx);
                        return -1;
                }
                if(!entry){
                        //the end
                        break;
                }
 
                av_log(NULL,AV_LOG_INFO,"%12"PRId64" %s\n",
                        entry->size,
                        entry->name);
 
                avio_free_directory_entry(&entry);//free entry
        }
 
        avio_close_dir(&ctx);
        return 0;
}

ffmpeg——重要的结构体

  • AVIOContext(I/O上下文)                           // 实现文件或者流的I/O操作
  • AVFormatContext(封装格式上下文)          // 管理媒体文件的格式和封装信息
  • AVCodecContext(编解码器上下文)          // 控制和配置音视频编解码器的行为
  • AVStream(音视频流)                               //  描述音视频流的属性
  • AVPacket (数据包)                                  // 用于在媒体文件、流之间传递数据
  • AVFrame(帧)                                         // 存储和传递音视频数据
  • AVDictionary(字典)                                 // 存储配置选项和元数据
  • AVFilterContext(滤镜上下文)                  // 处理音视频数据,应用滤镜效果。
  • SwsContext(图像转换上下文)                // 进行图像处理和转换
  • SwrContext(音频重采样上下文)            // 进行音频处理和转换

AVIOContext结构体,用于管理媒体文件或者网络流的输入和输出操作 

AVCodecContext结构体,包含了音频和视频编解码器的配置信息,如编码参数、解码参数、码率控制等。部分字段说明:

codec编解码器的AVCodec,比如指向AVCodec ff_aac_latm_decoder
width, height图像的宽高(只针对视频)
pix_fmt像素格式(只针对视频)
sample_rate采样率(只针对音频)
channels声道数(只针对音频)
sample_fmt采样格式(只针对音频

AVFormatContext结构体,是与多媒体文件格式相关的结构体,用于打开、读取和写入媒体文件。它包含了文件的格式信息、音视频流、文件I/O操作等。部分字段说明:

struct AVInputFormat* iformat输入媒体的AVInputFormat(输入数据的封装格式),比如指向AVInputFormatff_flv_demuxer
struct AVOutputFormat *oformat用于指定输出文件的格式以及文件写入的操作函数
AVIOContext *pb用于读取和写入媒体数据的 I/O 上下文
unsigned int nb_streams输入媒体的AVStream 个数
AVStream** streams输入媒体的AVStream []数组
int64_t start_time, duration媒体文件的起始时间戳和持续时间(以微秒为单位),计算方式可以参考av_dump_format()函数
int bit_rate输入媒体的码率

AVStream结构体,代表了音频或视频流,包括编解码参数、时间基准、时间戳等信息。部分字段说明

index标识该视频/音频流
time_base该流的时基, PTS*time_base=真正的时间(秒)
avg_frame_rate该流的帧率
duration该视频/音频流长度
codecpar编解码器参数属性

AVPacket结构体,用于存储音频或视频数据包,包括编码后的数据和时间戳。部分字段说明:

pts显示时间戳
dts解码时间戳
data压缩编码数据
size压缩编码数据大小
pos数据的偏移地址
stream_index所属的AVStream

AVFrame结构体,用于存储音频或视频帧的数据。它包括像素数据、采样数据、时间戳等。部分字段说明:

data解码后的图像像素数据(音频采样数据)
linesize对视频来说是图像中一行像素的大小;对音频来说是整个音频帧的大小
width, height图像的宽高(只针对视频)
key_frame是否为关键帧(只针对视频) 
pict_type帧类型(只针对视频) 。例如I, P, B
sample_rate音频采样率(只针对音频)
nb_samples音频每通道采样数(只针对音频)
pts显示时间戳

AVDictionary结构体,用于存储键值对,通常用于配置选项的传递和存储。

SwrContext结构体,用于音频重采样,支持不同采样率、通道数之间的转换

SwsContext结构体,用于图像转换,支持不同的像素格式和大小之间的转换

AVFilterContext结构体,用于配置和管理滤镜,包括音频滤镜和视频滤镜。

 播放器框架

有关参考常用api:

https://www.cnblogs.com/linuxAndMcu/p/12041359.html

官方api文档:FFmpeg: Main Page

音视频八股文(6)-- ffmpeg大体介绍和内存模型 


ffmpeg——多媒体文件简单操作

        多媒体文件是一个容器(也可以理解为包装盒,常见的mp4、flv、mkv都是不同的包装盒 ),可以存放很多数据,最常见的有字幕数据、视频数据、音频数据。

        在容器中有很多流(Stream/Track),流媒体文件中不同的流之数据不会相交的,比如音频流和视频流就是各自独立的。

        每种流是由不同的编码器编码的,每条流数据在多媒体文件中是经过压缩的,但是其使用压缩的编码器都是不一样的。比如音频有可能是MP3,有可能是AAC,视频常见的压缩器有可能是H264或者H265。

        从流中读出的数据称为包,在一个包中包含着一个或者多个帧。

ffmpeg操作流数据的基本步骤:

 提取音、视频数据

//提取多媒体文件的音频数据

//编译链接:gcc -o extra_audio extra_audio.c `pkg-config --libs --cflags libavutil libavformat libavcodec`

//执行 ./extra_audio test.mp4 1.aac

#include<stdio.h>
#include<libavutil/log.h>
#include <libavformat/avformat.h>


int main(int argc, char* argv[])
{
	
	int ret = -1;
	int idx = -1;
	
	// 1. 处理输入参数
	char* src, * dst;

	AVFormatContext* pFmtCtx = NULL;	// 多媒体上下文
	AVFormatContext* oFmtCtx = NULL;	// 目标文件上下文信息

	const AVOutputFormat* outFmt = NULL;		// 输出文件格式信息
	AVStream* outStream = NULL;			//输出文件的流
	AVStream* inStream = NULL;			//输入文件的流

	AVPacket pkt;		// 包


	av_log_set_level(AV_LOG_DEBUG);
	if (argc < 3) {	//该可执行程序  源文件   目标文件
		av_log(NULL, AV_LOG_INFO, "Arguments must be more than 3.");
		exit(-1);
	}
	src = argv[1];
	dst = argv[2];

	// 2、打开多媒体文件(包含文件头和文件体)
	if ((ret = avformat_open_input(&pFmtCtx, src, NULL, NULL)))
	{
		av_log(NULL, AV_LOG_ERROR, "%s\n", av_err2str(ret));
		exit(-1);
	}
	
	// 3、从多媒体文件中找到音频流
	idx = av_find_best_stream(pFmtCtx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);	//  在文件中找到“最佳”流。AVMEDIA_TYPE_AUDIO 提取音频 //视频 AVMEDIA_TYPE_VIDEO
	if (idx < 0) {
		av_log(pFmtCtx, AV_LOG_ERROR, "Does not include audio stream\n");
		goto _ERROR;
	}

	// 4、打开目的文件的上下文
	oFmtCtx = avformat_alloc_context();
	if (!oFmtCtx) {
		av_log(NULL, AV_LOG_ERROR, "No Memory!\n");
		goto _ERROR;
	}
		//设置输出文件的参数
	outFmt = av_guess_format(NULL, dst, NULL);	// 返回与所提供参数最匹配的已注册输出格式列表中的输出格式(NULL-系统匹配)
	oFmtCtx->oformat = outFmt;
	
	// 5、为目的文件创建一个新的音频流
	outStream = avformat_new_stream(oFmtCtx, NULL);
	
	// 6、设置输出音频参数
	inStream = pFmtCtx->streams[idx];
	avcodec_parameters_copy(outStream->codecpar, inStream->codecpar);	//将源文件的内容复制到目的文件 
	outStream->codecpar->codec_tag = 0;	// 根据多媒体文件自动识别编解码器
	
		//上下文信息与输出文件绑定
	ret = avio_open2(&oFmtCtx->pb, dst, AVIO_FLAG_WRITE, NULL,NULL);
	if (ret < 0) {
		av_log(NULL, AV_LOG_ERROR, "%s", av_err2str(ret));
		goto _ERROR;

	}

	// 7、写多媒体文件头(包含多媒体的类型、版本等信息)到目标文件
	ret = avformat_write_header(oFmtCtx, NULL);
	if (ret < 0) {
		av_log(oFmtCtx, AV_LOG_ERROR, "%s", av_err2str(ret));
		goto _ERROR;

	}

	// 8、从源多媒体文件中读到音频数据
	while (av_read_frame(pFmtCtx, &pkt) >= 0) {  // 从多媒体文件读取到帧数据
		if (pkt.stream_index == idx) {	// 判断是否是我们需要的流(之前找到的音频流)
			// 修改目标文件时间戳 pts dts 时长 duration
			pkt.pts = av_rescale_q_rnd(pkt.pts, inStream->time_base, outStream->time_base, (AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
			pkt.dts = pkt.pts;	// 音频文件dts 和 pts 相等,视频需要通过av_rescale_q_rnd()计算dts
			pkt.duration = av_rescale_q(pkt.duration, inStream->time_base, outStream->time_base);
			pkt.stream_index = 0;	// 流编号信息
			pkt.pos = -1;			// 偏移位置
			av_interleaved_write_frame(oFmtCtx, &pkt);		// 将音频帧写入目标文件中
			av_packet_unref(&pkt);
		}
	}
	// 9、写多媒体文件尾到文件中
	av_write_trailer(oFmtCtx);

	// 10、将申请的资源释放掉
_ERROR:
	if (pFmtCtx) {
		avformat_close_input(&pFmtCtx);
		pFmtCtx = NULL;
	}
	if (oFmtCtx->pb) {
		avio_close(oFmtCtx->pb);
	}
	if (oFmtCtx) {
		avformat_free_context(oFmtCtx);
		oFmtCtx = NULL;
	}
	return 0;
}
//提取多媒体文件的视频数据

//编译链接:gcc -o extra_video extra_video.c `pkg-config --libs --cflags libavutil libavformat libavcodec`

//执行 ./extra_video test.mp4 2.h264

#include<stdio.h>
#include<libavutil/log.h>
#include <libavformat/avformat.h>


int main(int argc, char* argv[])
{

	int ret = -1;
	int idx = -1;

	// 1. 处理输入参数
	char* src, * dst;

	AVFormatContext* pFmtCtx = NULL;	// 多媒体上下文
	AVFormatContext* oFmtCtx = NULL;	// 目标文件上下文信息

	const AVOutputFormat* outFmt = NULL;		// 输出文件格式信息
	AVStream* outStream = NULL;			//输出文件的流
	AVStream* inStream = NULL;			//输入文件的流

	AVPacket pkt;		// 包


	av_log_set_level(AV_LOG_DEBUG);
	if (argc < 3) {	//该可执行程序  源文件   目标文件
		av_log(NULL, AV_LOG_INFO, "Arguments must be more than 3.");
		exit(-1);
	}
	src = argv[1];
	dst = argv[2];

	// 2、打开多媒体文件(包含文件头和文件体)
	if ((ret = avformat_open_input(&pFmtCtx, src, NULL, NULL)))
	{
		av_log(NULL, AV_LOG_ERROR, "%s\n", av_err2str(ret));
		exit(-1);
	}

	// 3、从多媒体文件中找到视频流
	idx = av_find_best_stream(pFmtCtx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);	//  在文件中找到“最佳”流。
	if (idx < 0) {
		av_log(pFmtCtx, AV_LOG_ERROR, "Does not include audio stream\n");
		goto _ERROR;
	}

	// 4、打开目的文件的上下文
	oFmtCtx = avformat_alloc_context();
	if (!oFmtCtx) {
		av_log(NULL, AV_LOG_ERROR, "No Memory!\n");
		goto _ERROR;
	}
	//设置输出文件的参数
	outFmt = av_guess_format(NULL, dst, NULL);	// 返回与所提供参数最匹配的已注册输出格式列表中的输出格式(NULL-系统匹配)
	oFmtCtx->oformat = outFmt;

	// 5、为目的文件创建一个新的视频流
	outStream = avformat_new_stream(oFmtCtx, NULL);

	// 6、设置输出视频参数
	inStream = pFmtCtx->streams[idx];
	avcodec_parameters_copy(outStream->codecpar, inStream->codecpar);	//将源文件的内容复制到目的文件 
	outStream->codecpar->codec_tag = 0;	// 根据多媒体文件自动识别编解码器

	//上下文信息与输出文件绑定
	ret = avio_open2(&oFmtCtx->pb, dst, AVIO_FLAG_WRITE, NULL, NULL);
	if (ret < 0) {
		av_log(NULL, AV_LOG_ERROR, "%s", av_err2str(ret));
		goto _ERROR;

	}

	// 7、写多媒体文件头(包含多媒体的类型、版本等信息)到目标文件
	ret = avformat_write_header(oFmtCtx, NULL);
	if (ret < 0) {
		av_log(oFmtCtx, AV_LOG_ERROR, "%s", av_err2str(ret));
		goto _ERROR;

	}

	// 8、从源多媒体文件中读到视频数据
	while (av_read_frame(pFmtCtx, &pkt) >= 0) {  // 从多媒体文件读取到帧数据
		if (pkt.stream_index == idx) {	// 判断是否是我们需要的流(之前找到的视频流)
			// 修改目标文件时间戳 pts dts 时长 duration
			pkt.pts = av_rescale_q_rnd(pkt.pts, inStream->time_base, outStream->time_base, (AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
			pkt.dts = av_rescale_q_rnd(pkt.dts, inStream->time_base, outStream->time_base, (AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
			pkt.duration = av_rescale_q(pkt.duration, inStream->time_base, outStream->time_base);
			pkt.stream_index = 0;	// 流编号信息
			pkt.pos = -1;			// 偏移位置
			av_interleaved_write_frame(oFmtCtx, &pkt);		// 将视频帧写入目标文件中
			av_packet_unref(&pkt);
		}
	}
	// 9、写多媒体文件尾到文件中
	av_write_trailer(oFmtCtx);

	// 10、将申请的资源释放掉
_ERROR:
	if (pFmtCtx) {
		avformat_close_input(&pFmtCtx);
		pFmtCtx = NULL;
	}
	if (oFmtCtx->pb) {
		avio_close(oFmtCtx->pb);
	}
	if (oFmtCtx) {
		avformat_free_context(oFmtCtx);
		oFmtCtx = NULL;
	}
	return 0;
}

用到API:

/* 打开一个输入流并读取报头。编解码器没有打开。流必须用avformat_close_input()关闭。


参数:
    @param ps指向用户提供的AVFormatContext(由avformat_alloc_context)。可能是指向NULL的指针,在这种情况下,AVFormatContext由this分配函数并写入ps。注意,用户提供的AVFormatContext将被释放失败。

    @param url打开的流的url。

    @param fmt如果非null,该参数强制使用特定的输入格式。否则格式自动检测。

    @param options一个由AVFormatContext和demuxer-private填充的字典选项。返回时,此参数将被销毁并替换为包含未找到的选项的字典。可能为NULL。


成功时返回0,失败时返回负AVERROR。
*/

int avformat open input(AVFormatContext *ps, 
                        const char *url, 
                        const AVinputFormat *fmt,
                        AVDictionary **options)
//分配一个AVFormatContext。
// avformat_free_context()可以用来释放上下文和框架在其中分配的所有内容。

AVFormatContext *avformat_alloc_context(void);
/*
    在文件中找到“最佳”流。最佳流是根据各种启发式确定的,因为最可能是用户期望的。如果decoder参数非null, av_find_best_stream将为流的编解码器找到默认的解码器;找不到解码器的流将被忽略。


参数:

    *  @param ic                 媒体文件句柄
    * @param type                 视频,音频,字幕等
    * @param wanted_stream_nb    用户请求的流编号或-1为自动选择
    * @param related_stream    尝试找到一个流相关(例如:在同一个程序中)到这个,如果没有,则为-1
    * @param decoder_ret       如果非null,返回所选流的解码器
    * @param flags             当前没有定义


@return
    如果成功,返回非负的流号,如果没有找到请求类型的流,返回AVERROR_STREAM_NOT_FOUND,如果找到流但没有解码器,返回AVERROR_DECODER_NOT_FOUND

@note
如果av_find_best_stream返回成功并且decoder_ret不是NULL,那么*decoder_ret保证被设置为有效的AVCodec。

*/
int av_find_best_stream(AVFormatContext *ic,
                        enum AVMediaType type,
                        int wanted_stream_nb,
                        int related_stream,
                        const AVCodec **decoder_ret,
                        int flags);
/*返回与所提供参数最匹配的已注册输出格式列表中的输出格式,如果没有匹配则返回NULL。

@param short_name    if non-NULL检查short_name是否与注册格式的名称匹配
@param filename     if non-NULL检查filename是否以注册格式的扩展名结束
@param mime_type     if non-NULL检查mime_type是否与注册格式的MIME类型匹配

*/

const AVOutputFormat *av_guess_format(const char *short_name,
                                      const char *filename,
                                      const char *mime_type);

/*向媒体文件添加新的流。
    在解模时,由read_header()中的解模器调用。如果标志AVFMTCTX_NOHEADER在s.ctx_flags中设置,那么它也可以在read_packet()中被调用

    当复用时,应该在avformat_write_header()之前由用户调用。
    用户需要调用avformat_free_context()来清理分配,由avformat_new_stream()。

参数:
    @param s  媒体文件句柄
    @param c  未使用,不做任何事情

@return 新创建的流,错误时返回NULL。

*/

AVStream *avformat_new_stream(AVFormatContext *s, const AVCodec *c);
/*
***创建并初始化一个AVIOContext来访问url表示的资源。

参数:
  @param s      用于返回指向创建的AVIOContext的指针。在失败的情况下,指向的值被设置为NULL。
  @param url     要访问的资源
  @param flags   控制如何打开url所指示的资源的标志
  @param int_cb   在协议级别使用的中断回调
  @param options 私有选项的字典,返回时此参数将被销毁并替换为包含未找到选项的字典可能为NULL。
  @return >= 0如果成功,则为an对应的负值失败时的AVERROR代码


注:当url所指示的资源以读+写方式打开时,AVIOContext只能用于写。

*/
int avio_open2(AVIOContext **s, const char *url, int flags,
               const AVIOInterruptCB *int_cb, AVDictionary **options);
/*
*** 返回流的下一帧。此函数返回存储在文件中的内容,而不验证是否存在用于解码器的有效帧。它将把存储在文件中的内容分割成帧,并为每次调用返回一个帧。它不会省略有效帧之间的无效数据,以便为解码器提供可能用于解码的最大信息。
    如果成功,返回的数据包将被引用计数(pkt->但已设置)并无限期有效。当不再需要该数据包时,必须使用av_packet_unref()释放该数据包。对于视频,数据包只包含一帧。对于音频,如果每帧有一个已知的固定大小(例如PCM或ADPCM数据),它包含一个整数帧数。如果音频帧具有可变大小(例如MPEG音频),则它包含一个帧。
    pkt->pts, pkt->dts和pkt->duration在AVStream中总是设置为正确的值。Time_base单位(并猜测格式是否不能提供它们)。如果视频格式有b帧,pkt->pts可以是AV_NOPTS_VALUE,所以如果不解压缩有效载荷,最好依赖pkt->dts。

return: 如果OK则返回0,错误或文件结束时返回< 0。如果出现错误,pkt将为空白(就好像它来自av_packet_alloc())。

注:注意PKT将被初始化,所以它可能是未初始化的,但它不能包含需要释放的数据。
*/
int av_read_frame(AVFormatContext *s, AVPacket *pkt);

多媒体格式转封装:

音视频解码流程: 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/557572.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Eagle for Mac v1.9.13注册版:强大的图片管理工具

Eagle for Mac是一款专为Mac用户设计的图片管理工具&#xff0c;旨在帮助用户更高效、有序地管理和查找图片资源。 Eagle for Mac v1.9.13注册版下载 Eagle支持多种图片格式&#xff0c;包括JPG、PNG、GIF、SVG、PSD、AI等&#xff0c;无论是矢量图还是位图&#xff0c;都能以清…

AndroidStudio AGP 7+, 编译aar并输出到本地仓库

1 编写构建gradle脚本代码 1.1 配置publication和repository 在指定moudle目录下新建名为"maven-publish.gradle"文件&#xff0c;其声明的publication和repository如下所示&#xff1a; apply plugin: maven-publish// This creates a task called publishReleas…

《星光对话》系列直播:带你入门数据要素

2020年12月9日&#xff0c;财政部提出企业数据资源可作为资产列入财务报表&#xff0c;打响数据要素“1N”的第一枪&#xff1b; 2022年12月2日&#xff0c;《关于构建数据基础制度更好发挥数据要素作用的意见》“数据二十条”通过提出构建数据产权、流通交易、收益分配、安全治…

维护SQLite的私有分支(二十六)

返回&#xff1a;SQLite—系列文章目录 上一篇&#xff1a;SQLite、MySQL 和 PostgreSQL 数据库速度比较&#xff08;本文阐述时间很早比较&#xff0c;不具有最新参考性&#xff09;&#xff08;二十五&#xff09; 下一篇&#xff1a;SQLite数据库中JSON 函数和运算符 1…

# 从浅入深 学习 SpringCloud 微服务架构(三)注册中心 Eureka(1)

从浅入深 学习 SpringCloud 微服务架构&#xff08;三&#xff09;注册中心 Eureka&#xff08;1&#xff09; 段子手168 1、微服务的注册中心 注册中心可以说是微服务架构中的”通讯录”&#xff0c;它记录了服务和服务地址的映射关系。 在分布式架构中服务会注册到这里&am…

美易官方:美债美元黄金继续涨?

全球金融市场波动加剧&#xff0c;投资者对避险资产的需求不断升温。在这一背景下&#xff0c;“投行老将”们纷纷发表观点&#xff0c;认为避险情绪尚未结束&#xff0c;美债、美元和黄金等避险资产有望继续上涨。 巴克莱一位资深投资银行家表示&#xff0c;由于担心中东冲突升…

在Linux系统中搜索当前路径及其子目录下所有PDF文件中是否包含特定字符串

目录标题 方法一&#xff1a;pdfgrep方法二&#xff1a;使用find和xargs与pdftotext&#xff08;将PDF转换为文本&#xff09;组合&#xff0c;然后用grep搜索 方法一&#xff1a;pdfgrep pdfgrep -ri "rockchip" .方法二&#xff1a;使用find和xargs与pdftotext&am…

动手学深度学习11 权重衰退

动手学深度学习11 权重衰退 1. 权重衰退2. 代码实现3. QA 视频&#xff1a; https://www.bilibili.com/video/BV1UK4y1o7dy/?spm_id_fromautoNext&vd_sourceeb04c9a33e87ceba9c9a2e5f09752ef8 电子书&#xff1a; ttps://zh-v2.d2l.ai/chapter_multilayer-perceptrons/wei…

Mamba 学习

Vision Mamba U-Mamba 以后的趋势&#xff1a; 1.Mamba模型机机制上和transform一样&#xff0c;但是参数量上做了改进&#xff0c;可以直接替代 2.vision上可以实时处理

视频太大怎么压缩变小?8种方法随时压缩视频大小

视频太大怎么压缩变小&#xff1f;视频压缩方式分为两种&#xff0c;有损压缩和无损压缩&#xff0c;什么是有损什么是无损压缩&#xff0c;什么时候视频用无损压缩更好&#xff1f;什么时候用有损压缩更好&#xff1f;如何调整视频参数实现基本无损压缩&#xff1f; 今天就借助…

小红书笔记写作方法和技巧分享,纯干货!

很多小伙伴感叹小红书笔记流量就是一个玄学&#xff0c;有时精心撰写的笔记却没有人看&#xff0c;自己随便写的笔记却轻轻松松上热门。实际上你还是欠点火候&#xff0c;小红书笔记写作是有一套方法和技巧的&#xff0c;总归是有套路的&#xff0c;如果你不知道&#xff0c;请…

数仓建模—物理数据模型

文章目录 数仓建模—物理数据模型什么是物理数据模型物理数据模型示例如何构建物理数据模型物理数据模型与逻辑数据模型逻辑模型和物理模型之间有什么关系逻辑数据模型的好处物理数据模型的好处数仓建模—物理数据模型 前面我们讲了数据模型和逻辑数据模型,你可以参考前面的文…

【JAVA进阶篇教学】第四篇:JDK8中函数式接口

博主打算从0-1讲解下java进阶篇教学&#xff0c;今天教学第四篇&#xff1a;JDK8中函数式接口。 在 Java 8 中&#xff0c;函数式接口是指只包含一个抽象方法的接口。这种接口可以用作 Lambda 表达式的类型&#xff0c;从而使得函数式编程在 Java 中变得更加方便和灵活。下面…

【题解】NC398 腐烂的苹果(多源BFS)

https://www.nowcoder.com/practice/54ab9865ce7a45968b126d6968a77f34?tpId196&tqId40529&ru/exam/oj 从每个腐烂的苹果开始使用广度优先遍历&#xff08;bfs&#xff09; class Solution {int n, m;int dx[4] {0, 0, 1, -1};int dy[4] {1, -1, 0, 0};vector<v…

C++ STL 容器 deque

目录 1. deque 对象1.1 内部表示1.2 底层数据结构1.3 分段连续1.4 重新分配 2. deque 迭代器 本文测试环境 gcc 13.1 1. deque 对象 1.1 内部表示 deque 为我们提供了一个双端队列&#xff0c;即可以在队头进行 push、pop&#xff0c;可以在队尾进行 push、pop deque 容器擅…

电弧的产生机理

目录&#xff1a; 1、起弧机理 2、电弧特点 3、电弧放电特点 4、实际意义 1&#xff09;电力开关装置 2&#xff09;保险丝 1、起弧机理 电弧的本质是一种气体放电现象&#xff0c;可以理解为绝缘情况下产生的高强度瞬时电流。起弧效果如下图所示&#xff1a; 在电场的…

pyplot+pandas实现操作excel及画图

1、安装jupyter lab pip install jupyterlab # 启动 建议在指定的项目文件夹下 开启cmd窗口并执行 jupyter lab 启动后会自动打开浏览器访问 2、安装依赖 pip install matplotlib pip install xlrd pip install pandas 3、读取excel import pandas as pddf pd.read_excel(hi…

一文带你了解什么是国际短信

什么是国际短信&#xff1f; 国际短信&#xff0c;也叫国际短消息&#xff0c;是指中国大陆以外的国家或地区运营商与用户之间发送和接收短信息的业务&#xff0c;是一种实现国际间沟通交流与信息触达的便捷方式&#xff0c;可广泛应用于出海游戏、跨境电商、在线社交、实体零…

「探索C语言内存:动态内存管理解析」

&#x1f320;先赞后看&#xff0c;不足指正!&#x1f320; &#x1f388;这将对我有很大的帮助&#xff01;&#x1f388; &#x1f4dd;所属专栏&#xff1a;C语言知识 &#x1f4dd;阿哇旭的主页&#xff1a;Awas-Home page 目录 引言 1. 静态内存 2. 动态内存 2.1 动态内…

比特币上最有价值的BRC-20,你了解吗?

BRC20 是比特币网络上发行同质化Token 的实验性格式标准&#xff0c;由domodata 于2023 年3 月8 日基于 Ordinal 协议创建。 类似于以太坊的 ERC20 标准&#xff0c;它规定了以太坊上发行 Token 的名称、发行量、转账等功能&#xff0c;所有基于以太坊开发的 Token 合约都遵守这…
最新文章