我是靠谱客的博主 优雅猎豹,最近开发中收集的这篇文章主要介绍linux 264,LINUX下用FFMPEG解碼264,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

OK, 由於項目需要, 需要在嵌入式平台上將264的視頻流解碼出來, 所以用到了FFMPEG。

一、平台搭建

首先,需要搭建好平台,  我用的是2.4版本的FFMPEG。 從官網下載下來的FFMPEG, 解壓出來, 進到目錄后直接可以運行 # ./configure     一般會提示 “yasm/nasm not found or too old. Use --disable-yasm for a crippled build.”, 系統並沒有預先裝yasm, 所以提示出錯。 此時只需要照着提示加個選項 #  ./configure --disable-yasm。 后面一般都不會有其它問題,根據典型的安裝,先編譯 #make   后安裝 # sudo make install

二、編寫代碼

前面平台如果搭建都沒什么問題的話,下面可以進行編碼, 其實說是說編碼,也只是參考別人的來改而已, 主要是百度以及參照官網提供的例子程序來進行修改的。 在此,遇到問題多看官網上的說明, 尤其是幫助文檔 點擊打開鏈接。 並且需要找到對應的版本幫助文檔才有用, 網上很多代碼都是老版本的, 有不少方法都更新了,不再是從前那個接口, 所以這點對新手來說要多注意。

OK,閑話不多說,下面貼出代碼, 因為代碼量也不大,沒有對其進行封裝處理,將就着用一下吧。

#include "stdio.h"

#include "stdlib.h"

#include "libavformat/avformat.h"

#include "libavdevice/avdevice.h"

#include "libswresample/swresample.h"

#include "libavutil/opt.h"

#include "libavutil/channel_layout.h"

#include "libavutil/parseutils.h"

#include "libavutil/samplefmt.h"

#include "libavutil/fifo.h"

#include "libavutil/intreadwrite.h"

#include "libavutil/dict.h"

#include "libavutil/mathematics.h"

#include "libavutil/pixdesc.h"

#include "libavutil/avstring.h"

#include "libavutil/imgutils.h"

#include "libavutil/timestamp.h"

#include "libavutil/bprint.h"

#include "libavutil/time.h"

#include "libavutil/threadmessage.h"

#include "libavfilter/avcodec.h"

#include "libavcodec/avcodec.h"

#if HAVE_SYS_RESOURCE_H

#include

#include

#include

#elif HAVE_GETPROCESSTIMES

#include

#endif

#if HAVE_GETPROCESSMEMORYINFO

#include

#include

#endif

#if HAVE_SYS_SELECT_H

#include

#endif

#if HAVE_TERMIOS_H

#include

#include

#include

#include

#elif HAVE_KBHIT

#include

#endif

#if HAVE_PTHREADS

#include

#endif

#include

#include "libavutil/avassert.h"

#define MAX_LEN 1024 * 50

此方法參考官網的例子

static void pgm_save(unsigned char *buf, int wrap, int xsize, int ysize,

FILE *f)

{

// FILE *f;

int i;

// f = fopen(filename,"w");

// fprintf(f, "P5n%d %dn%dn", xsize, ysize, 255);

for (i = 0; i < ysize; i++)

fwrite(buf + i * wrap, 1, xsize, f);

// fclose(f);

}

int main()

{

//下面初始化h264解碼庫

//avcodec_init();

av_register_all();

AVFrame *pFrame_ = NULL;

/* find the video encoder */

AVCodec *videoCodec = avcodec_find_decoder(CODEC_ID_H264);//得到264的解碼器類

if(!videoCodec)

{

printf("avcodec_find_decoder errorn");

return -1;

}

AVCodecParserContext *avParserContext = av_parser_init(CODEC_ID_H264);//得到解析幀類,主要用於后面的幀頭查找

if(!avParserContext)

{

printf("av_parser_init errorn");

return -1;

}

AVCodecContext *codec_ = avcodec_alloc_context3(videoCodec);//解碼會話層

if(!codec_)

{

printf("avcodec_alloc_context3 errorn");

return -1;

}

//初始化參數,下面的參數應該由具體的業務決定

codec_->time_base.num = 1;

codec_->frame_number = 1; //每包一個視頻幀

codec_->codec_type = AVMEDIA_TYPE_VIDEO;

codec_->bit_rate = 0;

codec_->time_base.den = 25;//幀率

codec_->width = 352;//視頻寬

codec_->height = 288;//視頻高

if(avcodec_open2(codec_, videoCodec, NULL) >= 0)//打開解碼器

{

pFrame_ = avcodec_alloc_frame();// Allocate video frame 成功打開解碼器后, 此時可以分配幀內存, 當然你也可以在后面每次都分配、釋放, 在此我省功夫, 只在開始分配一次

if (!pFrame_) {

fprintf(stderr, "Could not allocate video framen");

exit(1);

}

}

else

{

printf("avcodec_open2 errorn");

return -1;

}

AVPacket packet = {0};

int dwBufsize = 10;

int frameFinished = dwBufsize;//這個是隨便填入數字,沒什么作用

av_init_packet(&packet);

packet.data = NULL;//這里填入一個指向完整H264數據幀的指針

packet.size = 0;//這個填入H264數據幀的大小

FILE *myH264 = fopen("test3.264", "rb");//解碼的文件264

if(myH264 == NULL)

{

perror("cant open 264 filen");

return -1;

}

FILE *yuvfile = fopen("my264.yuv", "wb");//成功解碼后保存成的YUV文件, 可以用YUV工具打開瀏覽

if(yuvfile == NULL)

{

perror("cant open YUV filen");

return -1;

}

int readFileLen = 1;

char readBuf[MAX_LEN];

unsigned char *parseBuf = malloc(20*MAX_LEN);//這個地方浪費了我一個下午時間, 當時我用的是棧內存,即unsigned char parseBuf[20*MAX_LEN], 結果運行程序一直報錯, 此處需要用堆內存才能正常解碼

int parseBufLen = 0;

int frameCount = 0;

printf("begin...n");

printf("readBuf address is %xn", readBuf);

while(readFileLen > 0)//開始解碼工作

{

//printf("begin...n");

readFileLen = fread(readBuf, 1, sizeof(readBuf), myH264);//首先從文件里讀出數據

if(readFileLen <= 0)

{

printf("read overn");

break;

}

else

{

int handleLen = 0;

int handleFileLen = readFileLen;

while(handleFileLen > 0)

{

int nLength = av_parser_parse2(avParserContext, codec_, &parseBuf, &parseBufLen, readBuf + handleLen, handleFileLen, 0, 0, 0);//查找264幀頭

handleFileLen -= nLength;

handleLen += nLength;

if(parseBufLen <= 0)//當parseBufLen大於0時,說明查找到了幀頭

{

continue;

}

packet.size = parseBufLen;//將查找到的幀長度送入

packet.data = parseBuf;//將查找到的幀內存送入

//printf("parseBuf address is %xn", parseBuf);

while(packet.size > 0)

{//下面開始真正的解碼

int decodeLen = avcodec_decode_video2(codec_, pFrame_, &frameFinished, &packet);

if(decodeLen < 0)

break;

packet.size -= decodeLen;

packet.data += decodeLen;

if(frameFinished > 0)//成功解碼

{

int picSize = codec_->height * codec_->width;

//int newSize = picSize * 1.5;

//申請內存

//unsigned char *buf = malloc(newSize);

int height = pFrame_->height;

int width = pFrame_->width;

//printf("OK, get datan");

//printf("Frame height is %dn", height);

//printf("Frame width is %dn", width);

frameCount ++;

printf("Frame count is %dn", frameCount);

pgm_save(pFrame_->data[0], pFrame_->linesize[0],//保存Y

codec_->width, codec_->height, yuvfile);

pgm_save(pFrame_->data[1], pFrame_->linesize[1],//保存U

codec_->width/2, codec_->height/2, yuvfile);

pgm_save(pFrame_->data[2], pFrame_->linesize[2],//保存V

codec_->width/2, codec_->height/2, yuvfile);

///有了YUV數據, 后面可以用FFMPEG提供的轉換方法,將其轉成RGB數據,進行后續的顯示或其它的圖像處理工作

}

else

printf("failed to decodecn");

}

}

}

}

//釋放工作

avcodec_close(codec_);

av_free(codec_);

av_free_packet(&packet);

av_frame_free(&pFrame_);

fclose(yuvfile);

fclose(myH264);

}

值得一提的是,代碼在開始時遇到一個奇怪的問題, 編譯后運行到解碼方法avcodec_decode_video2時總提示錯誤:[h264 @ 0x1a791e0] no frame!     后來發現是我將一個內存弄成棧而不是堆內存(在代碼注釋中有說明),而FFMPEG卻不對其解碼, 這一點讓我很奇怪, 一定要堆內存么?

三、編譯

編譯說起來其實是一件很容易的事,不過這也弄了快一天的時間, 主要是我第一次用這個FFMPEG的庫, 沒想到它的方法依賴性那么強, 就是庫與庫之前的依賴性比較強, 在編譯過程對引用庫的順序要特別注意, 不然會報很多方法沒有找到的錯。  只要順序搞對, 其它遇到一些方法沒找到時主要是沒引用上相應的庫,那些都好辦。順序一般為 -lavformat  -lavcodec -lswresample -lavuti

總結一下, 解碼264原來以為是一件挺難搞的事, 整了兩三天發現其實也挺容易的, 關鍵得多看幫助文檔。  寫到這里, 后面提供我的工程,在工程里帶有用於測試用的264文件。  工程鏈接:點擊打開鏈接           YUV查看工具: 點擊打開鏈接

最后

以上就是优雅猎豹为你收集整理的linux 264,LINUX下用FFMPEG解碼264的全部内容,希望文章能够帮你解决linux 264,LINUX下用FFMPEG解碼264所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(55)

评论列表共有 0 条评论

立即
投稿
返回
顶部