使用ffmpeg进行解码的基本流程 和几个重要函数
来源:互联网 发布:建筑学需要用的软件 编辑:程序博客网 时间:2024/06/05 01:11
最近学习了如和使用 ffmpeg进行解码视频和音频 以及转码等
其实在使用ffmpeg的流程基本都是相同的
1. 将输入的文件转为常量字符(音频或者视频文件)
2.注册ffmpeg的组件(在这里可以通过使用av_regiest_all()来进行偷懒操作,将所有的组件都进行注册)
3.注册晚组件之后就开始封装全局的上下文AVFormatContext (使用avformat_aloc_context方法获取)
4.开始检查能否打开视频或音频文件 ,检测是否可以读取音视频文件信息,查找视频流,检测编码器是否可以打开 等等 检测性操作
--avformat_open_input :该方法用于检测是否可以打开音视频文件
--avformat_find_stream_info:该方法用于查看音视频信息
--通过遍历所有的流 并判断流的类型可以寻找到视频流的位置
--通过编码id 查找 该音视频的编码方式进行对应的解码
--avcodec_open2 :该方法可以用于检测能否打开解码器
5.检查完所有的硬性条件之后,便开始一帧一帧的解码 并可以在这里对解码的内容进行操作(如转码,绘制到空间上等)
6.关闭,释放所有的指针变量等
7.返回所需的内容
示例:该示例实在android studio 下进行转码操作的一个示例
JNIEXPORT void JNICALL Java_utils_VideoUtils_decode(JNIEnv *env, jclass jcls, jstring input_jstr, jstring output_jstr) { //1.将视频文件输入 //需要转码的视频文件(输入的视频文件) //讲视频文件转换为常量字符 __const char* input_cstr =(env)->GetStringUTFChars(input_jstr,NULL); __const char* output_cstr=(env)->GetStringUTFChars(output_jstr,NULL); //2.注册所有的组件 av_register_all(); //3.封装格式上下文,统领全局的结构体 类似于applicationContext 在这里保存了视频文件封装的相关信息 AVFormatContext *formatContext =avformat_alloc_context(); //4.打开输入视频文件 if(avformat_open_input(&formatContext,input_cstr,NULL,NULL)!=0){ LOGE("%s","无法打开输入视频文件"); return; } //5.获取视频文件信息 if(avformat_find_stream_info(formatContext,NULL)<0){ LOGE("%s","无法获取视频文件信息"); return; } //6.获取视频流的索引位置 ------遍历所有类型的流 找到视频流 int v_stream_idx=-1; int i=0; for(;i<formatContext->nb_streams;i++){ //比对是否是视频流 //if(formatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO){ 在这里 我的 AVMEDIA_TYPE_VIDEO 视频流的type 类型 不被识别 原因 缺少改头文件 avutil.h if(formatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO){ v_stream_idx=i; break; } } if(v_stream_idx==-1){ LOGE("%s","找不到视频流"); return; } //7.获取视频流的编码 //无解的奇怪bug 无法定义AVCodecContext 指针 强行不使用该指针变量进行后续操作 //AVCodecContext *avcodeContext =formatContext->streams[v_stream_idx]->codec; //AVCodec *pCodec = avcodec_find_decoder(avcodeContext->codec_id); //存储编解码器信息的结构体 AVCodec *avCodec=avcodec_find_decoder(formatContext->streams[v_stream_idx]->codec->codec_id); if((formatContext->streams[v_stream_idx]->codec)==NULL){ LOGE("%s","找不到解码器"); return; } //8 打开解码器 if(avcodec_open2((formatContext->streams[v_stream_idx]->codec),avCodec,NULL)<0){ LOGE("%s","解码器打不开"); return; } //输出一下 解码器的信息 //LOGI("视频的文件格式:%s",formatContext->iformat->name); //LOGI("视频时长:%d",(formatContext->duration)/1000); //LOGI("视频的宽高:%d",formatContext->streams[v_stream_idx]->codec->width,formatContext->streams[v_stream_idx]->codec->height); //LOGI("解码器的名称:%s",avCodec->name); //9开辟缓冲区 分配内存 AVPacket *packet = (AVPacket*)av_malloc(sizeof(AVPacket)); //内存 AVFrame * avFrame=av_frame_alloc(); //YUV AVFrame *avFrameYUV =av_frame_alloc(); //缓冲区分配内存 uint8_t *out_buffer= (uint8_t *) av_malloc(avpicture_get_size(AV_PIX_FMT_YUV420P, formatContext->streams[v_stream_idx]->codec->width, formatContext->streams[v_stream_idx]->codec->height)); //初始化缓冲区 avpicture_fill((AVPicture *) avFrameYUV, out_buffer, AV_PIX_FMT_YUV420P, formatContext->streams[v_stream_idx]->codec->width, formatContext->streams[v_stream_idx]->codec->height); //设置用于转码的参数 转之前的 宽 高 格式 转之后的宽高 等 struct SwsContext *sws_ctx=sws_getContext(formatContext->streams[v_stream_idx]->codec->width, formatContext->streams[v_stream_idx]->codec->height, formatContext->streams[v_stream_idx]->codec->pix_fmt, formatContext->streams[v_stream_idx]->codec->width, formatContext->streams[v_stream_idx]->codec->width, AV_PIX_FMT_YUV420P,SWS_BICUBIC,NULL,NULL,NULL); int got_picture, ret; FILE *wb=fopen(output_cstr, "wb+"); //用于记录第多少帧 的变量 int frame_count = 0; //10 开始一帧一帧读取压缩数据 while(av_read_frame(formatContext,packet)>=0){ //判断 如果是视频压缩数据 (通过判断视频流的索引位置) if(packet->stream_index==v_stream_idx){ //开始解码(一帧) 根据返回值ret 进行判断 小于0 出错 等于0 解码完成 大于0正在解码 //avPack 解码 ret=avcodec_decode_video2(formatContext->streams[v_stream_idx]->codec,avFrame,&got_picture,packet); if(ret<0){ LOGE("%s","解码出错"); return; } if(got_picture){ sws_scale(sws_ctx, (const uint8_t *const *) avFrame->data, avFrame->linesize, 0, formatContext->streams[v_stream_idx]->codec->height, avFrameYUV->data, avFrameYUV->linesize); //YUV 输出 写入文件 //几选像素点 宽乘以高 int y_size=formatContext->streams[v_stream_idx]->codec->width*formatContext->streams[v_stream_idx]->codec->height; //写入Y fwrite(avFrameYUV->data[0],1,y_size,wb); //写入U fwrite(avFrameYUV->data[1],1,y_size,wb); //写入V fwrite(avFrameYUV->data[2],1,y_size,wb); frame_count++; LOGI("解码第%d帧",frame_count); } } //释放资源 av_free_packet(packet); } //关闭文件流 上下文引用等 fclose(wb); avcodec_close(formatContext->streams[v_stream_idx]->codec); avformat_free_context(formatContext); //返回所需的数据 env->ReleaseStringChars(input_jstr, (const jchar *) input_cstr); env->ReleaseStringChars(output_jstr, (const jchar *) output_cstr);}
0 0
- 使用ffmpeg进行解码的基本流程 和几个重要函数
- FFMpeg的解码流程
- FFMpeg的解码流程
- FFMpeg的解码流程
- FFMpeg的解码流程
- FFMpeg的解码流程
- FFMpeg的解码流程
- FFMpeg的解码流程
- FFMpeg的解码流程
- FFMpeg的解码流程
- FFMpeg的解码流程
- FFMpeg的解码流程
- FFMpeg的解码流程
- FFMpeg的解码流程
- FFMpeg的解码流程
- FFMpeg对视频文件进行解码的大致流程
- ffmpeg对视频文件进行解码的大致流程
- ffmpeg对视频文件进行解码的大致流程
- 【集群管理】数据挂载mount命令及批处理dsh命令
- 原生 Hive 1.2.1 的安装
- angular自己最近使用的一种筛选方法
- NMAP分布式扫描工具dnmap
- mybatis系列-动态 SQL(四)
- 使用ffmpeg进行解码的基本流程 和几个重要函数
- (一)第一个窗口程序
- Lintcode(S)落单的数
- 如何查看Eclipse版本
- IOS开发UI篇之──键盘添加工具条
- python如何实现清屏
- 百度一面
- IE兼容border-radius的方法
- 消息与事件、如何快速添加容易忘的消息和事件?