大致流程播放器类的项目初始化大同小异,所以本文章将作为所有播放器类项目初始化 *** 作的记录。
- 注册FFmpeg相关的组件。
- 打开输入的媒体流文件,通过判断输入文件名后缀或读取头部信息,检测输入流的协议信息和封装格式信息。
- 读取媒体流的数据包来获取并赋值流(AVStream)的信息。
- 找到并打开匹配且已注册的解码器。
-
该函数调用avcodec_register_all()注册了和编解码器有关的组件,如硬件加速、解码器、编码器、Parser和Bitstream Filter;同时注册了复用器、解复用器和协议处理器。
-
注册函数都大同小异,都是设定一个全局静态的链表头,将注册的组件以链表的形式保存起来,同时进行一些初始化 *** 作。
-
如编解码器的注册函数如下,可知其最终是调用了avcodec_register这个函数。
#define REGISTER_ENCODER(X,x) { \ extern AVCodec ff_##x##_encoder; \ if(CONFIG_##X##_ENCODER) avcodec_register(&ff_##x##_encoder); } #define REGISTER_DECODER(X,x) { \ extern AVCodec ff_##x##_decoder; \ if(CONFIG_##X##_DECODER) avcodec_register(&ff_##x##_decoder); } #define REGISTER_ENCDEC(X,x) REGISTER_ENCODER(X,x); REGISTER_DECODER(X,x) /* 如REGISTER_ENCDEC(MPEG4, mpeg4)即 extern AVCodec ff_mpeg4_encoder; if(CONFIG_MPEG4_ENCODER) avcodec_register(&ff_mpeg4_encoder); extern AVCodec ff_mpeg4_decoder; if(CONFIG_MPEG4_DECODER) avcodec_register(&ff_mpeg4_decoder); */
-
avcodec_register函数如下,其中first_avcodec是全局静态变量,该注册函数即是把所有的编解码器都以链表形式,保存在以first_avcodec为链表头的链表中,同时进行一些初始化 *** 作。
static AVCodec *first_avcodec = NULL; void avcodec_register(AVCodec *codec) { AVCodec **p; avcodec_init(); p = &first_avcodec; while (*p != NULL) p = &(*p)->next; *p = codec; codec->next = NULL; if (codec->init_static_data) codec->init_static_data(codec); }
-
-
该函数用于打开一个输入的媒体流,同时通过判断输入文件名后缀或读取头部信息,检测输入流的协议信息和封装格式信息;并初始化管理输入/输出数据流的结构体AVIOContext、初始化输入格式结构体AVInputFormat。
-
int avformat_open_input(AVFormatContext ** ps, const char *url, const AVInputFormat *fmt, AVDictionary **options)
- ps:用户提供的AVFormatContext结构体,调用成功后对其进行处理,若为NULL,则会自动使用avformat_alloc_context申请空间。
- url:输入的媒体流名字。
- fmt:用于强制使用该特定的输入格式,若为NULL,则会自动检测格式。
- options:附加的一些选项。
- 该函数通过读取媒体流的数据包来获取并赋值流(AVStream)的信息,中途包括查找并打开解码器、读取数据包并解码等 *** 作。
- int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
- ic:描述媒体流的结构体AVFormatContext。
- options:附加的一些选项。
- 该函数根据编解码器id,找到匹配且已注册的解码器;注册 *** 作发生在av_register_all的avcodec_register中,即是从以first_avcodec为链表头的链表中,找寻匹配的解码器。
- const AVCodec* avcodec_find_decoder(enum AVCodecID id)
- id:编解码器id,如AV_CODEC_ID_MJPEG,AV_CODEC_ID_H264等。
- 该函数用于初始化编解码器上下文AVCodecContext和相应解码器AVCodec ,以使用相应解码器进行解码 *** 作。
- int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options)
- avctx:需要初始化的编解码器上下文AVCodecContext。
- codec:需要打开的解码器AVCodec 。
- options:附加的一些配置参数。
-
定义如下数据类型
/*解码器*/ class Decode { public: AVCodecContext *codec_ctx; //描述编解码器相关信息 AVCodec *codec; //描述编解码器 ...... int codec_config(AVCodecContext *ctx, enum AVMediaType _type); /*配置编解码器*/ private: enum AVMediaType type; ...... }; /*音频流*/ class AudioCtrl { public: class Decode dec; ...... private: }; /*媒体流*/ class MediaCtrl { public: AVFormatContext *fmt_ctx; AVStream *video_st, *audio_st; int audio_index, video_index; class AudioCtrl1 au; MediaCtrl(char *_media); ~MediaCtrl(); ...... private: char *media_name; ...... };
-
初始化 *** 作
MediaCtrl::MediaCtrl(char *_media) { int ret; AVCodecContext *codec_ctx = NULL; media_name = _media; /*注册ffmpeg组件,初始化SDL,同时完成相关初始化 *** 作*/ av_register_all(); //注册所有ffmpeg组件 if (avformat_network_init()) { /*初始化音视频格式网络连接*/ printf("init avformat error !\n"); } if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) { /*初始化SDL - 音视频和定时器*/ printf( "Could not initialize SDL - %s\n", SDL_GetError()); } fmt_ctx = avformat_alloc_context(); //申请AVFormatContext空间 if (fmt_ctx == NULL) { printf("alloc avformat error !\n"); } ret = avformat_open_input(&fmt_ctx, media_name, NULL, NULL); //打开音视频文件 if (ret != 0) { printf("can not open input AV file !\n"); } /*查找数据流信息,并从编码器信息中找到音频流信息*/ ret = avformat_find_stream_info(fmt_ctx, NULL); //查找数据流信息 if (ret != 0) { printf("can not get input AV stream info !\n"); } audio_index = -1; for (int i = 0; i < fmt_ctx->nb_streams; i ++) { if (fmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO && audio_index == -1) { audio_index = i; } else if (fmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO && video_index == -1) { video_index = i; } } codec_ctx = fmt_ctx->streams[audio_index]->codec; ret = au.dec.codec_config(codec_ctx, AVMEDIA_TYPE_AUDIO); //配置音频解码器 if (ret != 0) { printf("audio decoder config error\n"); } } int Decode::codec_config(AVCodecContext *ctx, enum AVMediaType _type) { int ret; codec_ctx = ctx; type = _type; switch (type) { case AVMEDIA_TYPE_AUDIO: codec = avcodec_find_decoder(ctx->codec_id); //获取音频流解码器 if (codec == NULL) { printf("can not find the audio codec !\n"); return -1; } ret = avcodec_open2(codec_ctx, codec, NULL); //打开音频流解码器 if (ret != 0) { printf("can not open the audio codec !\n"); return -1; } break; case AVMEDIA_TYPE_VIDEO: break; default: break; } return 0; }
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)