//注册FFMpeg
av_register_all();
//网络初始化
avformat_network_init();
//注册编解码器
avcodec_register_all();
//打开文件并且解析
avformat_open_input(&ic, url, NULL, NULL); ------------------------->AVFormatContext(里面包含AVStream)
//该函数可以读取一部分视音频数据并且获得一些相关的信息
avformat_find_stream_info(ic, NULL);
//找到对应流的索引
audioStream = av_find_best_stream(ic, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
//找到相应流的解码器
AVCodec *codec = avcodec_find_decoder(ic->streams[videoStream]->codecpar->codec_id);
//解码器初上下文-------->解码器始化缓存空间
AVCodecContext *vc = avcodec_alloc_context3(codec);
//把对应流的一些属性复制给解码器的缓存空间,相当于配置解码器的一些信息:宽 高 帧率 采样格式
avcodec_parameters_to_context(vc, ic->streams[videoStream]->codecpar);
//打开解码器
avcodec_open2(vc, 0, 0);
//读取音视频信息 //AVFormatContext *ic = NULL
av_read_frame(ic, pkt); //AVPacket *pkt = av_packet_alloc();
//把数据发送到数据空间缓冲区
re = avcodec_send_packet(vc, pkt);
//从数据空间缓冲区收到数据(这个就是原始数据)
avcodec_receive_frame(vc, frame);
//接收到原始数据后对视频进行转换
//对数据格式进行转换(包括大小)
sws_getCachedContext(struct SwsContext *context , int srcW , int srcH , enum AVPixelFormat srcFormat
int dstW , int dst H , enum AVPixelFormat dstFormat , int flag)
//对每一帧数据进行转换
sws_scale(struct SwsContext *context , srcSlice(高度 Slice[0]Slice[1]Slice[2]) , srcStride(对齐策略--->宽度) ,
srcSilceY(从哪一个位置计算) , srcSliceH(1280*720 H=720) , dst , dstStride)
AVFormatContext(里面包含AVStream)------>AVCondecContext----------->AVPacket---------->AVFrame
-----------------------华丽的分割线------------------------------------------
//注册FFMpeg
av_register_all();
//网络初始化
avformat_network_init();
//注册编解码器
avcodec_register_all();
//YUV--->RGB
sws_getCachedContext(struct SwsContext *context , int srcW , int srcH , enum AVPixelFormat srcFormat
int dstW , int dst H , enum AVPixelFormat dstFormat , int flag)------------>像素格式转换上下文(大小也转化)
//配置YUV的一些属性(数据格式 宽 高 对齐方式)
AVFrame *yuv = av_frame_alloc();
yuv->format = AV_PIX_FMT_YUV420P
yuv->width = inWidth
yuv->height = inHeight
yuv->pts = 0
//分配yuv空间
av_frame_get_buffer(yuv , (alignment多少位作为对齐策略)32)
(AVFrame *yuv = av_frame_alloc();
pcm->format = outSampleFmt; //样本格式
pcm->channels = channels; //通道数量
pcm->channel_layout = av_get_default_channel_layout(channels); //通道的格式
pcm->nb_samples = 1024; //一帧数量
av_frame_get_buffer(pcm , (alignment多少位作为对齐策略)32) //分配pcm的空间
)
//通过ID找到编码器
AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_H264);
//创造编码器的缓冲空间
AVCodecContext *vc = accodec_alloc_context3((AVCodec * code:代表参数) codec)
//为编码缓冲空间配置参数
vc->flags |= AV_CODEC_FLAG_GLOBAL_HEADER //全局参数
vc->codec_id = codec->id
vc->thread_count = 4 ;
针对视频的参数的配置
vc->bit_rate = 50*1024*8 (50KB) //码率, 压缩率 50*1024(kb)*8(字节数)
vc->width = inWidth
vc->height = inHight
vc->time_base(时间基数单位是秒) = {1 , fps}---------> 1 / fps--------------------------------------------------->需要回来重点看看
vc->time_framerate = {fps , 1}---------> fps / 1
vc->gop_size = 50 //画面组的大小,多少帧为一个关键帧,越大压缩率越好,但是容易丢失
vc->max_b_frames = 0; //当B帧为0的时候 , pts和bts显示一致
vc->pix_fmt = AV_PIX_FMT_YUV420P //像素格式
共工配置:全局参数 线程数量 压缩率
视频 : (数据格式 宽 高 时间基数 帧率 多少帧为一关键帧 B帧设置为0)
音频 : (采样率 数据格式 通道数 通道格式)
ac->bit_rate = 40000;
ac->sample_rate = sampleRate;
ac->sample_fmt = AV_SAMPLE_FMT_FLTP;
ac->channels = channels;
ac->channel_layout = av_get_default_channel_layout(channels);
//打开编码器
avcodec_open2(vc , 0 , 0);
//把每一帧数据转换成功后发送到缓冲区
sws_scale(struct SwsContext *context , srcSlice(高度 Slice[0]Slice[1]Slice[2]) , srcStride(对齐策略--->宽度) ,
srcSilceY(从哪一个位置计算) , srcSliceH(1280*720 H=720) , dst , dstStride)
//数据发送到编码器数据空间缓冲区
avcodec_send_frame(vc , yuv);
//AVPacket从编码器数据空间缓冲区收到数据
avcodec_receive_packet(vc , &pack);
//输出封装器的上下文(封装器的数据缓冲空间)
avformat_alloc_output_context2(&ic , 0 ,"flv(封装格式)" , "推流到指定的地址");
//首先创建AVStream,并从AVCodecContext获得数据
AVStream *vs = avformat_new_stream(ic , NULL);
avcodec_parameters_from_context(vs->codeccpar , vc);
//打开rtmp 的输出网络IO口
avio_open(&i->pb , " " , AVIO_FLAG_WRITE(写入的方式:有读 有写 有读写))
//写入封装头(它会 改变vs->timebase数值会被改掉,去取解码后的AVStream的timebase)
avformat_write_header(ic , NULL);
//推流
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)
av_interleaved_write_frame(ic , &pack)