【Android 音视频】FFmpeg解码视频生成yuv文件(附源码下载)

文摘   2024-10-22 07:31   广东  

这篇文章主要是介绍将MP4解码出yuv文件出来,先介绍一波yuv文件。


YUV是指亮度参量和色度参量分开表示的像素格式,而这样分开的好处就是不但可以避免相互干扰,还可以降低色度的采样率而不会对图像质量影响太大。

YUV是一个比较笼统地说法,针对它的具体排列方式,可以分为很多种具体的格式。


直接上主菜,如何将MP4解码出yuv文件


首先在java使用NDK,调用解码函数,输入MP4文件的路径和输出yuv文件的路径 decode(inputurl,outputurl);

接下来就是正式的解说FFmpeg相关函数的作用了。


先来一张图片,理清代码运行顺序。

接下来看注释,。。。。要是每一个函数详细的讲,我做不到,也写不完,重在熟悉流程。

//1.注册所有组件    av_register_all();    //初始网络流    avformat_network_init();    //封装格式上下文,统领全局的结构体,保存了视频文件封装格式的相关信息    pFormatCtx = avformat_alloc_context();    //2.打开输入视频文件    if(avformat_open_input(&pFormatCtx,input_str,NULL,NULL)!=0){        LOGE("Couldn't open input stream.\n");        return -1;    }    //3.获取视频文件信息    if(avformat_find_stream_info(pFormatCtx,NULL)<0){        LOGE("Couldn't find stream information.\n");        return -1;    }    //获取视频流的索引位置    //遍历所有类型的流(音频流、视频流、字幕流),找到视频流    videoindex=-1;    for(i=0; i<pFormatCtx->nb_streams; i++)        if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO){            videoindex=i;            break;        }    if(videoindex==-1){        LOGE("Couldn't find a video stream.\n");        return -1;    }    //只有知道视频的编码方式,才能够根据编码方式去找到解码器    //获取视频流中的编解码上下文    pCodecCtx=pFormatCtx->streams[videoindex]->codec;    //4.根据编解码上下文中的编码id查找对应的解码    pCodec=avcodec_find_decoder(pCodecCtx->codec_id);    if(pCodec==NULL){        LOGE("Couldn't find Codec.\n");        return -1;    }    if(avcodec_open2(pCodecCtx, pCodec,NULL)<0){        LOGE("Couldn't open codec.\n");        return -1;    }
pFrame=av_frame_alloc(); pFrameYUV=av_frame_alloc(); out_buffer=(unsigned char *)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height,1)); av_image_fill_arrays(pFrameYUV->data, pFrameYUV->linesize,out_buffer, AV_PIX_FMT_YUV420P,pCodecCtx->width, pCodecCtx->height,1);
//准备读取 //AVPacket用于存储一帧一帧的压缩数据(H264) //缓冲区,开辟空间 packet=(AVPacket *)av_malloc(sizeof(AVPacket));//用于转码(缩放)的参数,转之前的宽高,转之后的宽高,格式等 img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
//输出视频信息 sprintf(info, "[Input ]%s\n", input_str); sprintf(info, "%s[Output ]%s\n",info,output_str); sprintf(info, "%s[Format ]%s\n",info, pFormatCtx->iformat->name); sprintf(info, "%s[Codec ]%s\n",info, pCodecCtx->codec->name); sprintf(info, "%s[Resolution]%dx%d\n",info, pCodecCtx->width,pCodecCtx->height);

fp_yuv=fopen(output_str,"wb+"); if(fp_yuv==NULL){ printf("Cannot open output file.\n"); return -1; }
frame_cnt=0; time_start = clock();//6.一帧一帧的读取压缩数据 while(av_read_frame(pFormatCtx, packet)>=0){ //只要视频压缩数据(根据流的索引位置判断) if(packet->stream_index==videoindex){ //7.解码一帧视频压缩数据,得到视频像素数据 ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet); if(ret < 0){ LOGE("Decode Error.\n"); return -1; } //为0说明解码完成,非0正在解码 if(got_picture){ //AVFrame转为像素格式YUV420,宽高 //2 6输入、输出数据 //3 7输入、输出画面一行的数据的大小 AVFrame 转换是一行一行转换的 //4 输入数据第一列要转码的位置 从0开始 //5 输入画面的高度 sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize); //输出到YUV文件 //AVFrame像素帧写入文件 //data解码后的图像像素数据(音频采样数据) //Y 亮度 UV 色度(压缩了) 人对亮度更加敏感 //U V 个数是Y的1/4 y_size=pCodecCtx->width*pCodecCtx->height; fwrite(pFrameYUV->data[0],1,y_size,fp_yuv); //Y fwrite(pFrameYUV->data[1],1,y_size/4,fp_yuv); //U fwrite(pFrameYUV->data[2],1,y_size/4,fp_yuv); //V //Output info char pictype_str[10]={0}; switch(pFrame->pict_type){ case AV_PICTURE_TYPE_I:sprintf(pictype_str,"I");break; case AV_PICTURE_TYPE_P:sprintf(pictype_str,"P");break; case AV_PICTURE_TYPE_B:sprintf(pictype_str,"B");break; default:sprintf(pictype_str,"Other");break; } LOGI("Frame Index: %5d. Type:%s",frame_cnt,pictype_str); //释放资源 frame_cnt++; } } av_free_packet(packet); }


这只是说如何解码视频,还有音频没有解码,但是过程相似,甚至更简单。


项目地址:https://github.com/979451341/Audio-and-video-learning-materials/tree/master/FFmpeg(MP4%E8%BD%ACyuv%EF%BC%89


参考文章: https://www.cnblogs.com/CoderTian/p/6791638.html

(文章来源:http://blog.csdn.net/z979451341,作者:键盘舞者113)


《Android Camera开发入门》、《Camx初认识》已经上架,可以点击了解 -> 小驰成长圈 |期待见证彼此的成长 



觉得不错,点个赞呗 

小驰行动派
前世界500强软件开发工程师,记录分享工作和生活的思考。感谢关注,期待见证彼此的成长~
 最新文章