1. 程式人生 > 其它 >ffmpeg C語言視訊解碼

ffmpeg C語言視訊解碼

Mac FFmpeg視訊教學教材:https://pan.baidu.com/s/1Rta82eL0xiE_ciliTiA58g

提取碼:g7c4

視訊解碼生成YUV格式的原始資料

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include "libavcodec/avcodec.h"
  4 #include "libavformat/avformat.h"
  5 #include "libswscale/swscale.h"
  6 #include "libavutil/avutil.h"
  7 int main(){
8 //獲取輸入輸出檔名 9 char* src = "./test.mp4"; 10 char* desc = "./test.yuv"; 11 //封裝格式上下文,統領全域性的結構體,儲存了視訊檔案封裝格式的相關資訊 12 AVFormatContext * avf_ctx = avformat_alloc_context(); 13 int video_index = -1; 14 //設定日誌級別 15 av_log_set_level(AV_LOG_INFO); 16 //1.註冊所有元件 17 av_register_all();
18 //2.開啟視訊檔案 19 int ret = avformat_open_input(&avf_ctx,src,NULL,NULL); 20 if(ret < 0){ 21 av_log(NULL,AV_LOG_ERROR,"Can't open the file %s \n",src); 22 return -1; 23 } 24 //3.獲取視訊檔案資訊 25 ret = avformat_find_stream_info(avf_ctx,NULL); 26 if(ret < 0
){ 27 av_log(NULL,AV_LOG_ERROR,"can't find the stream"); 28 goto _end; 29 } 30 //列印視訊檔案資訊 31 av_dump_format(avf_ctx,0,src,0); 32 33 for(int i = 0; i < avf_ctx->nb_streams; i++){ 34 // av_log(NULL,AV_LOG_INFO,"第%d次",i); 35 if(avf_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO){ 36 video_index = i; 37 break; 38 } 39 } 40 if(video_index == -1){ 41 av_log(NULL,AV_LOG_ERROR,"can't find the video stream"); 42 goto _end; 43 } 44 45 //只有知道視訊的編碼方式,才能夠根據編碼方式去找到解碼器 46 //獲取視訊流中的編解碼上下文 47 AVCodecContext* avc_cxt = avf_ctx->streams[video_index]->codec; 48 49 //根據視訊中的編碼Id找到對應的解碼器 50 AVCodec *avc = avcodec_find_decoder(avc_cxt->codec_id); 51 if(avc == NULL){ 52 av_log(NULL,AV_LOG_ERROR,"can't find the decoder"); 53 goto _end; 54 } 55 56 // 開啟解碼器 57 ret = avcodec_open2(avc_cxt,avc,NULL); 58 if(ret < 0){ 59 av_log(NULL,AV_LOG_ERROR,"can't open the codec"); 60 goto _end; 61 } 62 63 // 輸出視訊資訊 64 av_log(NULL,AV_LOG_INFO,"視訊格式: %s \n",avf_ctx->iformat->name); 65 av_log(NULL,AV_LOG_INFO,"視訊時長: %lld s\n",avf_ctx->duration/1000000); 66 av_log(NULL,AV_LOG_INFO,"視訊寬x高: %d x %d \n",avc_cxt->width,avc_cxt->height); 67 av_log(NULL,AV_LOG_INFO,"視訊的解碼器的名稱:%s \n",avc->name); 68 //準備讀取 69 // AVPacket用於儲存一幀一幀的壓縮資料(H264) 70 //緩衝區,開闢空間 71 AVPacket * avp = (AVPacket*)av_malloc(sizeof(AVPacket)); 72 73 //AVFrame用於儲存解碼後的畫素資料(YUV) 74 //記憶體分配 75 AVFrame * avframe = av_frame_alloc(); 76 //YUV420 77 AVFrame *pFrameYUV = av_frame_alloc(); 78 //只有指定了AVFrame的畫素格式、畫面大小才能真正分配記憶體 79 //緩衝區分配記憶體 80 int8_t *buf = (int8_t*)av_malloc(avpicture_get_size(AV_PIX_FMT_YUV420P,avc_cxt->width,avc_cxt->height)); 81 82 //初始化緩衝區 83 avpicture_fill((AVPicture*)pFrameYUV , buf ,AV_PIX_FMT_YUV420P , avc_cxt->width,avc_cxt->height); 84 //用於轉碼(縮放)的引數,轉之前的寬高,轉之後的寬高,格式等 85 struct SwsContext *sws_ctx = sws_getContext(avc_cxt->width,avc_cxt->height,avc_cxt->pix_fmt, 86 avc_cxt->width,avc_cxt->height,AV_PIX_FMT_YUV420P, 87 SWS_BICUBIC,NULL,NULL,NULL); 88 89 int got_pic; 90 FILE *out_yuv = fopen(desc,"wb+"); 91 int frame_count = 0; 92 while(av_read_frame(avf_ctx,avp) >= 0){ 93 //只要視訊壓縮資料(根據流的索引位置判斷) 94 if(avp->stream_index == video_index){ 95 ret = avcodec_decode_video2(avc_cxt,avframe,&got_pic,avp); 96 if(ret < 0){ 97 av_log(NULL,AV_LOG_ERROR,"decode is error"); 98 goto _end; 99 } 100 //如果got_pic == 0 表示解碼完成 非0表示正在解碼 101 if(got_pic){ 102 //AVFrame轉為畫素格式YUV420,寬高 103 //2 6輸入、輸出資料 104 //3 7輸入、輸出畫面一行的資料的大小 AVFrame 轉換是一行一行轉換的 105 //4 輸入資料第一列要轉碼的位置 從0開始 106 //5 輸入畫面的高度 107 sws_scale(sws_ctx,avframe->data,avframe->linesize,0,avc_cxt->height,pFrameYUV->data,pFrameYUV->linesize); 108 // sws_scale(sws_ctx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height, 109 // pFrameYUV->data, pFrameYUV->linesize); 110 //輸出到YUV檔案 111 //AVFrame畫素幀寫入檔案 112 //data解碼後的影象畫素資料(音訊取樣資料) 113 //Y 亮度 UV 色度(壓縮了) 人對亮度更加敏感 114 //U V 個數是Y的1/4 115 int y_size = avc_cxt->width * avc_cxt->height; 116 fwrite(pFrameYUV->data[0], 1 ,y_size,out_yuv); 117 fwrite(pFrameYUV->data[1], 1 ,y_size / 4,out_yuv); 118 fwrite(pFrameYUV->data[2], 1 ,y_size / 4,out_yuv); 119 frame_count++; 120 av_log(NULL,AV_LOG_INFO,"解析完第%d幀\n",frame_count); 121 } 122 123 } 124 //釋放avpacket 125 av_free_packet(avp); 126 } 127 _end: 128 fclose(out_yuv); 129 av_frame_free(&avframe); 130 if(avc_cxt != NULL){ 131 avcodec_close(avc_cxt); 132 } 133 avformat_free_context(avf_ctx); 134 return 0; 135 }