函数原型:
void av_log_set_callback(void(*)(void *, int, const char *, va_list) callback)
设置日志打印的回调。
函数原型:
void av_log(void* avcl, int level, const char *fmt, ...)
输出日志。
av_malloc()就是简单的封装了系统函数malloc(),并做了一些错误检查工作。
函数原型
int avformat_alloc_output_context2(AVFormatContext **ctx, AVOutputFormat * oformat, const char * format_name, const char * filename)
初始化一个用于输出的AVFormatContext结构体
全局地初始化网络组件,需要用到网络功能的时候需要调用。
初始化libavformat和注册所有的复用器和解复用器和协议。
如果不调用这个函数,可以使用av_register_input_format()和av_register_out_format()来选择支持的格式。
AVPacket是存储压缩编码数据的数据结构。
通常是解复用器的输出,然后被传递给解码器。或者是编码器的输出,然后被传递给复用器。
AVPacket.size:data的大小。
AVPacket.dts:解码时间戳。
AVPacket.stream_index:标识该AVPacket所属的视频/音频流。
函数原型:
int av_copy_packet(AVPacket * dst, const AVPacket * src)
复制packet,包含内容。
函数原型:
void av_packet_unref(AVPacket * pkt)
解除packet引用的buffer,并且将其余的字段重置为默认值。
这是一个描述解码器上下文的数据结构,包含了众多编解码器需要的参数信息。
存储编码器信息的结构体。
主要包含以下信息:
const char *name:编解码器的名字的简称
const char *long_name:编解码器名字的全称
enum AVMediaType type:指明了类型,是视频,音频,还是字幕
enum AVCodecID id:ID,不重复
const AVRational *supported_framerates:支持的帧率(仅视频)
const enum AVPixelFormat *pix_fmts:支持的像素格式(仅视频),如RGB24、YUV420P等。
const int *supported_samplerates:支持的采样率(仅音频)
const enum AVSampleFormat *sample_fmts:支持的采样格式(仅音频)
const uint64_t *channel_layouts:支持的声道数(仅音频)
int priv_data_size:私有数据的大小
将原始分组数据作为解码器的输入。
在函数内部,会拷贝相关的AVCodecContext结构变量,将这些结构变量应用到解码的每一个包。例如
AVCodecContext.skip_frame参数通知解码器扔掉包含该帧的包。
创建AVCodecContext结构体。
将音频流信息拷贝到新的AVCodecContext结构体中。
释放AVCodecContext和与之相关联的所有内容,并且把指针置空。
原型:
int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options)
使用给定的AVCodec初始化AVCodecContext。
在使用这个函数之前需要使用avcodec_alloc_context3()分配的context。
原型
AVFrame* av_frame_alloc(void)
分配一个avframe和设置字段的默认值。分配出来的AVFrame必须使用av_frame_free()释放。
原型
int avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame)
返回解码器输出的解码数据
原型
int av_read_pause(AVFormatContext *s)
暂停网络流(例如RSTP流),使用av_read_play()重新开始。
原型
int av_read_play(AVFrameContext *s)
从当前的位置开始播放网络流(例如RSTP流)。
原型
int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
seek到某个时间点的关键帧。
原型
int av_read_frame(AVFormatContext *s, AVPacket *pkt)
读取码流中的音频若干帧或者视频一帧。例如,解码视频的时候,每解码一个视频帧,需要先调用av_read_frame()获得一帧视频的压缩数据,然后才能对该数据进行解码。
这个结构体描述了一个媒体文件或媒体流的构成和基本信息。
这是FFMpeg中最为基本的一个结构,是其他所有结构的根,是一个多媒体文件或流的根本抽象。
分配一个AVFormatContext,使用avformat_free_context来释放分配出来的AVFormatContext。
原型
int avformat_open_input(AVFormatContext **ps, const char *url, AVInputFormat *fmt, AVDictionary **options)
打开输出的流和读取头信息。需要使用avformat_close_input关闭打开的流。
原型
void avformat_close_input(AVFormatContext **s)
关闭一个打开的输入AVFormatContext,释放它得很所有内容和把指针(*s)置空。
原型
void av_dump_format(AVFormatContext *ic, int index, const char * url, int is_output)
打印输入或者输出格式的详细信息,比如duration, bitrate, streams, container, programs, metadata, side data, codec and time base。
原型
AVStream* avformat_new_stream(AVFormatContext *s, const AVCodec* c)
添加一个stream到媒体文件中。
原型
int avformat_write_header(AVFormatContext *s, AVDictionary ** options)
分配一个stream的私有数据而且写stream的header到一个输出的媒体文件。
像素格式的枚举类型,例如AV_PIX_FMT_YUV420P、AV_PIX_FMT_RGB24
媒体类型的枚举类型,如AVMEDIA_TYPE_VIDEO(视频)、AVMEDIA_TYPE_AUDIO(音频)、AVMEDIA_TYPE_SUBTITLE(字幕)
原型
int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
读取视音频数据来获取一些相关的信息。
原型:
av_file_map(const char *filename, uint8_t **bufptr, size_t * size, int log_offset, void * log_ctx)
读取文件名为filename的文件,并将其内容放入新分配的缓冲区中。
如果成功,则将bufptr设置为读缓冲区或映射缓冲区,并将size设置为*bufptr中缓冲区的字节大小。返回的缓冲区必须使用av_file_unmap()释放。
AVInputFormat为FFMPEG的解复用器对象。
该结构体描述一个媒体流。
该结构体描述了编码的流的属性。
原型
int avcodec_parameters_copy(AVCodecParameter *dst, const AVCodecParameter* src)
把src中的内容拷贝到dst中。
这个结构标识一个分数,num为分数,den为分母。
解码器标识ID的枚举类型。
原型
struct SwrContext* swr_alloc(void)
分配一个SwrContext,如果你使用这个函数,需要在调用swr_init()之前设置SwrContext的参数(手工的或者调用swr_alloc_set_opts())
libswresample 的上下文信息。
不像libavcodec和libavformat,这个结构是不透明的,如果你需要设置选项,你必须使用AVOptions而不能直接给这个结构的成员赋值。
原型
struct SwrContext* swr_alloc_set_opts(struct SwrContext *s,
int64_t out_ch_layout,
enum AVSampleFormat out_sample_fmt,
int out_sample_rate,
int64_t in_ch_layout,
enum AVSampleFormat in_sample_fmt,
int in_sample_rate,
int log_offset,
void *log_ctx
)
设置通用的参数,如果SwrContext为空则分配一个SwrContext。
原型
init swr_init(struct SwrContext *s)
在参数设置好以后初始化context。
原型
void swr_free(struct SwrContext ** s)
释放给定的SwrContext,并且把指针置为空。
原型
struct SwsContext* sws_getContext ( int srcW,
int srcH,
enum AVPixelFormat srcFormat,
int dstW,
int dstH,
enum AVPixelFormat dstFormat,
int flags,
SwsFilter * srcFilter,
SwsFilter * dstFilter,
const double * param
)
分配和返回一个SwsContext。
原型
int avio_open(AVIOContext **s, const char* filename, int flags)
创建和初始化一个AVIOContext用于访问filename指示的资源。
原型
int avio_closep(AVIOContext **s)
关闭AVIOContext** s打开的资源,释放它并且把指针置为空。
AV_ROUND_ZERO = 0, // Round toward zero. 趋近于0
AV_ROUND_INF = 1, // Round away from zero. 趋远于0
AV_ROUND_DOWN = 2, // Round toward -infinity. 趋于更小的整数
AV_ROUND_UP = 3, // Round toward +infinity. 趋于更大的整数
AV_ROUND_NEAR_INF = 5, // Round to nearest and halfway cases away from zero.
// 四舍五入,小于0.5取值趋向0,大于0.5取值趋远于0
原型
AVIOContext* avio_alloc_context(unsigned char* buffer,
int buffer_size,
int write_flag,
void* opaque,
int(*)(void *opaque, uint8_t *buf, int buf_size) read_packet,
int(*)(void *opaque, uint8_t *buf, int buf_size) write_packet,
int64_t(*)(void *opaque, int64_t offset, int whence) seek)
分配和初始化一个AVIOContext用于缓冲的I/O。之后需要使用avio_context_free()释放。
原型
void av_file_unmap(uint8_t *bufptr, size_t size)
取消映射或释放av_file_map()创建的缓冲区bufptr。
作者:smallest_one
链接:https://www.jianshu.com/p/b6b8c185a617
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
=======================================================
//打开一个封装文件
avformat_open_input(&fmt_ctx, input_filename, NULL, NULL);
//获得封装文件的streamer流信息
avformat_find_stream_info(fmt_ctx, NULL);
//获得封装文件中音频或者视频流的id号
av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
//获得音频或视频的codec
pCodecCtx = pFormatCtx->streams[0]->codec;
pCodec = avcodec_find_decoder(pCodecCtx->codec_id); /
origin_par = fmt_ctx->streams[video_stream]->codecpar;
codec = avcodec_find_decoder(origin_par->codec_id);
avcodec_find_encoder(AV_CODEC_ID_FLAC);
//打开codec
avcodec_open2(pCodecCtx, pCodec, NULL);
//根据AVCodec创建AVCodecContext
AVCodecContext* ctx = avcodec_alloc_context3((AVCodec*)enc);
//申请一帧画面的大小
byte_buffer_size = av_image_get_buffer_size(pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, 16);
byte_buffer = av_malloc(byte_buffer_size);
//申请音频的大小
byte_buffer_size = av_samples_get_buffer_size(NULL, pCodecCtx->channels, pCodecCtx->sample_rate, pCodecCtx->sample_fmt, 1);
//读取封装文件里的一包数据
av_read_frame(pFormatCtx, &rd_packet);
保存此一包数据(比如h264压缩数据)
fwrite(rd_packet.data, 1, rd_packet.size, video_fp);
//AVPAcket/AVFrame的申请以及初始化操作
av_init_packet(&pkt);
fr = av_frame_alloc();
//解码成yuv的AVFrame
avcodec_decode_video2(ctx, fr, &got_frame, &pkt);
//将AVFrame结构体保存的一帧yuv数据转换成unsigned char*
number_of_written_bytes = av_image_copy_to_buffer(byte_buffer, byte_buffer_size, (const uint8_t* const *)fr->data, (const int*) fr->linesize, ctx->pix_fmt, ctx->width, ctx->height, 1);/
out_frame_bytes = out_frame->nb_samples * out_frame->channels * sizeof(uint16_t);
memcpy(raw_out + out_offset, out_frame->data[0], out_frame_bytes);
out_offset += out_frame_bytes;
//AVFrame中buffer分配的两种方式(只是分配空间)
msg.frame->format = AV_PIX_FMT_RGBA;
msg.frame->width = 320;
msg.frame->height = 240;
ret = av_frame_get_buffer(msg.frame, 32); //int av_frame_get_buffer(AVFrame *frame, int align);
av_frame_get_buffer(in_frame, 32);
int av_image_alloc(uint8_t *pointers[4], int linesizes[4], int w, int h, enum AVPixelFormat pix_fmt, int align);
out_frame = av_frame_alloc();
avcodec_encode_audio2(enc_ctx, &enc_pkt, in_frame, &got_output); //编码
avcodec_decode_audio4(dec_ctx, out_frame, &got_output, &enc_pkt); //解码
//线程相关
av_thread_message_queue_send(wd->queue, &msg, 0);
av_thread_message_queue_recv(rd->queue, &msg, 0);
//FFmpeg进行H.264编码
yuv->pts = vpts;
vpts++;
avcodec_send_frame(vc, yuv);
avcodec_receive_packet(vc, &pack);
//FFmpeg进行视频格式封装和推流
pack.pts = av_rescale_q(pack.pts, vc->time_base, vs->time_base);
pack.dts = av_rescale_q(pack.dts, vc->time_base, vs->time_base);
pack.duration = av_rescale_q(pack.duration, vc->time_base, vs->time_base);
//像素格式转换
sws_getCachedContext()
sws_scale()
///////////////////////////////////////实例介绍////////////////////////////////////////////////////////////
https://linux.cn/article-10932-1.html
//封装格式变换:
ffmpeg -i z.flv -strict -2 z.mp4
ffmpeg -i z.flv -qscale 0 -strict -2 z.avi //-qscale 0 维持你的源视频文件的质量
//视频封装文件保存为音频文件
ffmpeg -i z.flv -vn -ar 44100 -ac 2 -ab 320 -f mp3 output.mp3
ffmpeg -i z.flv -vn(禁止视频) -ar 44100(采样率) -ac(通道数) 2 -ab(比特率) 320 -f(输出文件格式) mp3 output.mp3
//更改视频文件的分辨率
ffmpeg -i z.mp4 -filter:v scale=1280:720 -c:a copy output.mp4
ffmpeg -i input.mp4 -s 1280x720 -c:a copy output.mp4
ffmpeg -i z.mp4 -filter:v(视频过滤器) scale(拉伸过滤器)=1280:720 -c:a copy output.mp4
ffmpeg -i input.mp4 -s(尺寸裁剪) 1280x720 -c:a copy output.mp4
//压缩视频文件
//压缩音频文件(减少通道数,采样率,比特率等)
ffmpeg -i input.mp3 -ab 128 output.mp3
//从封装文件中获取视频流
ffmpeg -i z.mp4 -an video.mp4
//从封装文件中获取音频流
ffmpeg -i z.mp4 -vn audio.mp4
ffmpeg -i z.mp4 -vn -ab 256 -ar 48000 audio.mp3
//从视频中提取图片
ffmpeg -i input.mp4 -r 1 -f image2 image-%2d.png
ffmpeg -i input.mp4 -r(每秒钟提取一张图片(视频30s,则会提取30张图片)) 1 -f image2 image-%2d.png
//裁剪视频
ffmpeg -i input.mp4 -filter:v crop=320:120:200:150 output.mp4
ffmpeg -i input.mp4 -filter:v(视频过滤器) "crop(裁剪过滤器)=w:h:x:y" output.mp4
//转换一个视频的具体的部分(比如从视频开始到指定时间转换为其它格式)
ffmpeg -i input.mp4 -t 10.10 output.avi
ffmpeg -i input.mp4 -t(从视频开始到10s10ms处保存为avi格式) 10.10 output.avi
//使用开始和停止时间剪下一段媒体文件
ffmpeg -i z.mp4 -ss 00:00:10 -codec copy -t 50 output.mp4
ffmpeg -i z.mp4 -ss 00:00:10 -codec copy -t 50 output.avi
//设置视频的屏幕高宽比
ffmpeg -i input.mp4 -aspect 16:9 output.mp4
ffmpeg -i input.mp4 -aspect(设置宽高比) 16:9 output.mp4
//添加海报图像到音频文件
ffmpeg -loop 1 -i image-15.png -i audio.mp3 -c:v libx264 -c:a aac -strict experimental -b:a 192k -shortest output.mp4
ffmpeg -loop 1 -i inputimage.jpg -i inputaudio.mp3 -c:v(指定视频编解码模块) libx264 -c:a((指定音频编解码模块)) aac -strict experimental -b:a(?) 192k -shortest output.mp4
//切分视频文件为多个部分
ffmpeg -i input.mp4 -t 00:00:30 -c copy part1.mp4 -ss 00:00:30 -codec copy part2.mp4 //-c 和 -codec 同一个效果
//接合或合并多个视频部分到一个
ffmpeg -f concat -safe 0 -i join.txt -c copy output.mp4
//添加字幕到一个视频文件
ffmpeg -i input.mp4 -i subtitle.srt -map 0 -map 1 -c copy -c:v libx264 -crf 23 -preset veryfast output.mp4
//增加/减少视频播放速度
ffmpeg -i input.mp4 -vf "setpts=0.5*PTS" output.mp4
//创建动画的 GIF
ffmpeg -ss 00:00:20 -i sample.mp4 -to 10 -r 10 -vf scale=200:-1 cutekid_cry.gif
===================================================================
该函数在所有基于FFmpeg
的应用程序中几乎都是第一个被调用的
这个函数把全局的解码器,编码器等结构体注册到一些全局的对象表里,以便后面跑表调用
注册的类型:复用器,解复用器,编码器,解码器,包解析器,BitStreamFilter(位流处理器)等av_register_all
调用了avcodec_register_all
,avcodec_register_all
注册了和编解码器有关的组件:硬件加速器,解码器,编码器,Parser,Bitstream Filter。av_register_all除了调用
avcodec_register_all之外,还注册了复用器,解复用器,协议处理器
下面附上复用器,解复用器,协议处理器的代码
av_register_output_format
av_register_input_format
ffurl_register_protocol
avcodec_register_all
注册了和编解码器有关的组件:硬件加速器,解码器,编码器,Parser,Bitstream Filter。
av_register_hwaccel()
avcodec_register()
av_register_parser()
av_register_bitstream_filter()
内存操作的几个常见函数位于 libavutil\mem.c
先说下size_t
,这个类型在FFmpeg
中多次出现,它的作用其实就是为了增强程序的可移植性而定义的,不同系统上,定义size_t
可能不一样,它实际上就是unsigned int
为什么要内存对齐:内存对齐是什么就不说了,c语言的,很多也有点忘记了,直接看结论吧:内存不对齐对cpu对性能是有影响的
av_malloc()
CONFIG_MEMORY_POISONING
,因为这个宏默认都是为0的,源码函数可精简为
void *av_malloc(size_t size)
{
void *ptr = NULL;
/* let's disallow possibly ambiguous cases */
if (size > (max_alloc_size - 32))
return NULL;
ptr = malloc(size);
if(!ptr && !size) {
size = 1;
ptr= av_malloc(1);
}
return ptr;
所以可以看出来,av_malloc()
只是封装了系统的malloc()
,并且做了一些错误检查的工作
av_realloc
av_malloc()
一样,除去没用的宏,精简为
void *av_realloc(void *ptr, size_t size)
{
/* let's disallow possibly ambiguous cases */
if (size > (max_alloc_size - 32))
return NULL;
return realloc(ptr, size + !size);
}
可以看出来,av_realloc()
其实就是封装系统的realloc()
av_mallocz()
av_mallocz()
可以理解为av_mallocz()
+zeromemory
void *av_mallocz(size_t size)
{
void *ptr = av_malloc(size);
if (ptr)
memset(ptr, 0, size);
return ptr;
}
可以看出来就是调用了av_malloc(size)
之后,又调用memset()
将分配的内存设置为0
av_calloc()
av_mallocz()
void *av_calloc(size_t nmemb, size_t size)
{
if (size <= 0 || nmemb >= INT_MAX / size)
return NULL;
return av_mallocz(nmemb * size);
}
从代码中可以看出,它调用av_mallocz()
分配了nmemb * size个字节的内存
av_free()
void av_free(void *ptr)
{
free(ptr);
}
就是封装了free()
av_freep()
av_free()
,并且在释放内存之后将目标指针设置为NULL
void av_freep(void *arg)
{
void **ptr = (void **)arg;
av_free(*ptr);
*ptr = NULL;
}