第一章 音视频-FFmpeg解码流程和对应结构参数意
第二章 音视频-FFmpeg对应解析格式说明
第三章 音视频-FFmpeg对应AVFrame解码处理思路和用途
第四章 音视频-FFmpeg实现播放器思维
第五章 音视频-FFmpeg实现播放器解封装、读AVPacket包
第六章 音视频-FFmpeg实现播放器解码和对应数据处理
媒体文件进行解封装,在做播放器步骤前一个章节进行解封装,解封装可以自己进行C++ 或者c语言封装一个通过方法,获取相关结构体,结构体在第一章有做介绍,下面代码本人封装的一个通过方法,读取媒体文件可能只有音频或者视频,也可能同时有音视频,也可以只读取你要音频或者视频。
typedef struct {
AVCodecContext *video_dec_ctx;
AVCodecContext *audio_dec_ctx;
AVFormatContext *dec_fmt_ctx;
AVCodecContext *video_enc_ctx;
AVCodecContext *audio_enc_ctx;
double video_rotate;
int in_video_stream_index;
int in_audio_stream_index;
int out_video_stream_index; // 0
} media_info;
static double video_get_rotation(AVStream *st)
{
uint8_t* displaymatrix = av_stream_get_side_data(st,
AV_PKT_DATA_DISPLAYMATRIX, NULL);
double theta = 0;
if (displaymatrix)
theta = -av_display_rotation_get((int32_t*) displaymatrix);
theta -= 360*floor(theta/360 + 0.9/360);
if (fabs(theta - 90*round(theta/90)) > 2)
av_log(NULL, AV_LOG_WARNING, "Odd rotation angle.\n"
"If you want to help, upload a sample "
"of this file to ftp://upload.ffmpeg.org/incoming/ "
"and contact the ffmpeg-devel mailing list. (ffmpeg-devel@ffmpeg.org)");
return theta;
}
/**
* 打开文件
* @param filename 文件路径
* @param info 读取文件数据
* @param type选择读取是什么AVStream,0是读取所有
* @return
*/
int open_input_video(const char *filename,media_info **info,int type){
AVFormatContext* fmt_ctx =NULL;
AVDictionary *opts = NULL;
media_info* streamEntity;
int ret;
streamEntity = (media_info*)av_mallocz_array(1, sizeof(media_info));
if (!streamEntity){
MGTED_ERROR("=======av_mallocz_array=error==");
return AVERROR(ENOMEM);
}
streamEntity->in_video_stream_index = -1;
streamEntity->out_video_stream_index = 0;
streamEntity->video_rotate = 0;
if((ret=avformat_open_input(&fmt_ctx,filename,NULL,NULL))<0){
MGTED_ERROR("=======avformat_open_input=ret=%d",ret);
return ret;
}
fmt_ctx->probesize = 5000000 << 1;//从源文件中读取的最大字节数,单位为字节
fmt_ctx->max_analyze_duration = 90*AV_TIME_BASE;//是从文件中读取的最大时长,单位为 AV_TIME_BASE
if((ret=avformat_find_stream_info(fmt_ctx,NULL))<0){
MGTED_ERROR("=======avformat_find_stream_info==ret=%d",ret);
return ret;
}
for (int i = 0; i < fmt_ctx->nb_streams; ++i) {
AVStream* stream= fmt_ctx->streams[i];
if (type==1){
if(stream->codecpar->codec_type==AVMEDIA_TYPE_VIDEO){
continue;
}
} else if (type==2){
if(stream->codecpar->codec_type==AVMEDIA_TYPE_AUDIO){
continue;
}
}
if(stream->codecpar->codec_type==AVMEDIA_TYPE_VIDEO||
stream->codecpar->codec_type==AVMEDIA_TYPE_AUDIO){
AVCodec* codec=avcodec_find_decoder(stream->codecpar->codec_id);
if(!codec){
MGTED_ERROR("====avcodec_find_decoder=error=i=%d",i);
return AVERROR_DECODER_NOT_FOUND;
}
AVCodecContext* avCodecContext=avcodec_alloc_context3(codec);
if(!avCodecContext){
MGTED_ERROR("====avcodec_alloc_context3=error=i=%d",i);
return AVERROR(ENOMEM);
}
// avCodecContext->thread_count = 4; //设置解码器线程数
ret=avcodec_parameters_to_context(avCodecContext,stream->codecpar);
if(ret<0){
MGTED_ERROR("====avcodec_parameters_to_context=ret=%d=i=%d",ret,i);
return ret;
}
if(avCodecContext->codec_type==AVMEDIA_TYPE_VIDEO){
/* Open decoder */
if (!av_dict_get(opts, "threads", NULL, 0))
av_dict_set(&opts, "threads", "auto", 0);
av_dict_set(&opts, "refcounted_frames", "0", 0);
ret = avcodec_open2(avCodecContext,codec,NULL);
if(ret<0){
MGTED_ERROR("====avcodec_open2=ret=%d=i=%d",ret,i);
return ret;
}
int angle=video_get_rotation(stream);
streamEntity[0].video_dec_ctx = avCodecContext;
streamEntity[0].in_video_stream_index = i;
streamEntity[0].video_rotate = angle;
} else{
ret = avcodec_open2(avCodecContext,codec,NULL);
if(ret<0){
MGTED_ERROR("====avcodec_open2=ret=%d=i=%d",ret,i);
return ret;
}
streamEntity[0].audio_dec_ctx = avCodecContext;
streamEntity[0].in_audio_stream_index = i;
}
}
}
streamEntity[0].dec_fmt_ctx=fmt_ctx;
*info = streamEntity;
return ret;
}
下面对媒体文件进行读包,下面代码封装媒体读包处理,直播流要进行改,正常读包可以参考,为什么要读包,对相应包可以做对应解码,通过上面代码解封装可以获取dec_fmt_ctx格式上下文就可以读报。
while(1){
AVPacket packet = { .data = NULL, .size = 0 };
ret=av_read_frame(info->dec_fmt_ctx,&packet);
if(ret>=0){
if(packet.stream_index==AVMEDIA_TYPE_VIDEO ){//视频包
av_packet_unref(&packet);
} else if(packet.stream_index==AVMEDIA_TYPE_AUDIO){//音频包
av_packet_unref(&packet);
} else{
av_packet_unref(&packet);
}
} else{
av_packet_unref(&packet);
if (ret == AVERROR(EAGAIN)) {
av_usleep(10000);//延迟10ms
}else if (ret ==AVERROR_EOF) {//结束
break;
} else{//错误
break;
}
}
}