android 视频解码yuv,Android 音視頻深入 九 FFmpeg解碼視頻生成yuv文件(附源碼下載)...

項目地址,求star

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

這一次是將MP4解碼出yuv文件出來,先介紹一波yuv文件

YUV是指亮度參量和色度參量分開表示的像素格式,而這樣分開的好處就是不但可以避免相互干擾,還可以降低色度的采樣率而不會對圖像質量影響太大。YUV是一個比較籠統地說法,針對它的具體排列方式,可以分為很多種具體的格式。

直接上主菜,如何將MP4解碼出yuv文件

首先在java使用NDK,調用解碼函數,輸入MP4文件的路徑和輸出yuv文件的路徑

decode(inputurl,outputurl);

接下來就是正式的解說FFmpeg相關函數的作用了

先來一張圖片,理清代碼運行順序

79de5852297a9cf718a0deb901ba8cd0.png

接下來看注釋,。。。。要是每一個函數詳細的講,我做不到,也寫不完,重在熟悉流程

//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; inb_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://www.cnblogs.com/CoderTian/p/6791638.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值