标签:03 ffmpeg 解码sdk调用 h264转yuv420
制作一个H264文件
[root@localhost ~]# cd /home/ [root@localhost home]# wget http://sh.yinyuetai.com/uploads/videos/common/0E3E014EBF3448D901AF3519C4A1D4E0.mp4 [root@localhost home]# /ffmpeg -t 20 -i 0E3E014EBF3448D901AF3519C4A1D4E0.mp4 -c copy 1920_1080.h264
同样的Makefile文件:
[root@localhost 03]# cat makefile
FLAGS = -Wall -g
INCLUDEPATH = -I /home/ffmpeg_dev/include/
LIBPATH = -L /home/ffmpeg_dev/lib/
LIBS= -l avcodec -l pthread -l avutil -l m -l dl -l swresample
exe=yuv2h264
$(exe):
gcc main.c ${FLAGS} ${INCLUDEPATH} ${LIBPATH} ${LIBS} -o $@
clean:
rm -rf ${exe}
[root@localhost 03]#同样的自动编译运行脚本:
[root@localhost 03]# cat auto.sh make clean make ./yuv2h264 in.h264 out.yuv [root@localhost 03]#
这是一个可以正常运行的H264转YUV的程序:
[root@localhost 03_01]# cat main.c
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavfilter/avfiltergraph.h>
#include <libavfilter/buffersink.h>
#include <libavfilter/buffersrc.h>
#include <libavutil/opt.h>
#include <libavutil/pixdesc.h>
#include <sys/time.h>
//#define INBUF_SIZE 40960000
#define INBUF_SIZE 409600000
int main(int argc, char** argv)
{
FILE *pFileH264 = NULL;
FILE *pFileYUV = NULL;
pFileH264 = fopen(argv[1],"rb");
if( NULL == pFileH264 )
{
fprintf(stderr,"Could not open file \n");
exit(1);
}
pFileYUV = fopen(argv[2],"wb");
if(NULL == pFileYUV)
{
fprintf(stderr,"Open test.yuv fail\n");
exit(1);
}
avcodec_register_all();
AVCodec *codec;
AVCodecContext *c = NULL;
AVFrame *frame;
AVCodecParserContext *avParserContext;
int frame_count = 0;
//unsigned char buffer[INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];
unsigned char * inbuf = (unsigned char*)malloc(INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE);
//unsigned char *inbuf = buffer;
int got_frame;
int read_size;
memset(inbuf + INBUF_SIZE, 0, AV_INPUT_BUFFER_PADDING_SIZE);
codec = avcodec_find_decoder(AV_CODEC_ID_H264);
if( NULL == codec )
{
fprintf(stderr,"Codec not found\n");
exit(1);
}
c = avcodec_alloc_context3(codec);
if(NULL == c)
{
fprintf(stderr,"Could not allocate video codec context\n");
exit(1);
}
//初始化解码器所需要的参数,其实不设置也是可以正常解码的,因为264流中有对应的pps,sps相关结构
//里面包含解码所需要的相关信息
c->width = 640;
c->height = 360;
c->bit_rate = 1000;
c->time_base.num = 1;
c->time_base.den = 25;
c->codec_id = AV_CODEC_ID_H264;
c->codec_type = AVMEDIA_TYPE_VIDEO;
avParserContext = av_parser_init(AV_CODEC_ID_H264);
if( NULL == avParserContext)
{
fprintf(stderr,"Could not init avParserContext\n");
exit(1);
}
if(avcodec_open2(c,codec, NULL) < 0)
{
fprintf(stderr,"Could not open codec\n");
exit(1);
}
frame = av_frame_alloc();
if(NULL == frame)
{
fprintf(stderr,"Could not allocate video frame\n");
exit(1);
}
while(1)
{
//解码还有问题,因为avpkt不是一帧数据,而是有很多帧的数据,
//需要增加一个filter,一帧一帧过滤出来
read_size = fread(inbuf, 1,INBUF_SIZE, pFileH264);
printf("read_size_orig=%d\n",read_size);
if(read_size == 0)
{
break;
}
while(read_size)
{
unsigned char *buf = 0;
int buf_len = 0;
int parse_len = av_parser_parse2(avParserContext, c, &buf, &buf_len,
inbuf, read_size,
AV_NOPTS_VALUE,
AV_NOPTS_VALUE,
AV_NOPTS_VALUE);
printf("av_parser_parse2 len=[%d]\n", parse_len);
inbuf += parse_len;
read_size -= parse_len;
//printf("read_size=%d, parse_len=%d, buf_len=%d\n",read_size, parse_len, buf_len);
if(buf_len != 0)
{
AVPacket avpkt = {0};
av_init_packet(&avpkt);
avpkt.data = buf;
avpkt.size = buf_len;
time_t start ,end;
start = clock();
int decode_len = avcodec_decode_video2(c,frame, &got_frame, &avpkt);
end = clock();
printf("decoded frame used %d\n",end - start);
if(decode_len < 0)
fprintf(stderr,"Error while decoding frame %d\n",frame_count);
if(got_frame)
{
fprintf(stderr,"decode success\n");
int width = frame->width;
int height = frame->height;
unsigned char* yuv_buf = (unsigned char*)malloc(width * height *1.5);//可以放在while循环外面,这样就不用每次都申请,释放了
int i = 0;
//把解码出来的数据存成YUV数据,方便验证解码是否正确
for(i = 0; i < height; i++)
{
memcpy(yuv_buf + width * i, frame->data[0] + frame->linesize[0]*i, width);
if(i < height >> 1)
{
memcpy(yuv_buf + width * height + width *i / 2, frame->data[1] + frame->linesize[1]*i, width / 2);
memcpy(yuv_buf + width * height * 5 /4 + width * i / 2 ,frame->data[2] + frame->linesize[2]*i, width / 2);
}
}
fwrite(yuv_buf, sizeof(unsigned char),width * height * 1.5 ,pFileYUV);
free(yuv_buf);
frame_count++;
}
else
{
fprintf(stderr,"decode fail\n");
}
av_packet_unref(&avpkt);
}
}
}
//记得释放变量的空间
return 0;
}运行后产生的文件:
[root@localhost 03_01]# ll total 1.4G drwxr-xr-x. 2 root root 97 Oct 23 08:47 . drwxr-xr-x. 7 root root 4.0K Oct 23 08:42 .. -rwxr-xr-x. 1 root root 44 Oct 23 08:00 auto.sh -rw-r--r--. 1 root root 3.9M Oct 23 07:59 in.h264 -rw-r--r--. 1 root root 5.1K Oct 23 08:38 main.c -rwxr-xr-x. 1 root root 338 Oct 23 07:59 makefile -rw-r--r--. 1 root root 1.4G Oct 23 08:46 out.yuv -rwxr-xr-x. 1 root root 53K Oct 23 08:46 yuv2h264 [root@localhost 03_01]#
这是一个还没有调试好的H264转YUV的程序
[root@localhost 03]# cat main.c
#include <stdio.h>
#include <stdlib.h>
#include "libavcodec/avcodec.h"
#include "libavutil/opt.h"
#include "libavutil/channel_layout.h"
#include "libavutil/common.h"
#include "libavutil/imgutils.h"
#include "libavutil/mathematics.h"
#include "libavutil/samplefmt.h"
#define INBUF_SIZE 4096000 //缓存区太小,太大都不行
FILE *pFin = NULL;
FILE *pFout = NULL;
AVCodec *pCodec = NULL;
AVCodecContext *pCodecContext = NULL;
AVCodecParserContext *pCodecParserContext = NULL;
AVFrame *frame = NULL;
AVPacket pkt;
static void finish()
{
fclose(pFin);
fclose(pFout);
avcodec_close(pCodecContext);
av_free(pCodecContext);
av_frame_free(&frame);
}
static int open_codec()
{
avcodec_register_all();
av_init_packet(&pkt);
pCodec = avcodec_find_decoder(AV_CODEC_ID_H264);// 查找编解码器
if(NULL == pCodec)
{
printf("Not find H264 Codec\n");
return -1;
}
pCodecContext = avcodec_alloc_context3(pCodec);//分配AV context 空间
if(NULL == pCodecContext)
{
printf("avcodec_alloc_context3 err\n");
return -1;
}
if(pCodec->capabilities & AV_CODEC_CAP_TRUNCATED)//判断读取码流的状态 ,可能以截断的方式来读取
{
pCodecContext->flags |= AV_CODEC_CAP_TRUNCATED;
printf("AV_CODEC_CAP_TRUNCATED \n");
}
pCodecParserContext = av_parser_init(AV_CODEC_ID_H264);//根据码流格式,初始化解析器
if(NULL == pCodecParserContext)
{
printf("av_parser_init err\n");
return -1;
}
if(avcodec_open2(pCodecContext, pCodec, NULL) < 0)
{
printf("avcodec_open2 ERR \n");
return -1;
}
frame = av_frame_alloc();
if(NULL == frame)
{
printf("av_frame err\n");
return -1;
}
return 0;
}
static int init(int argc, char **argv)
{
const char *inputFileName = argv[1];
const char *oututFileName = argv[2];
pFin = fopen(inputFileName, "rb+");
if(NULL == pFin)
{
printf("open [%s],fail \n", inputFileName);
return -1;
}
printf("open [%s],OK \n", inputFileName);
pFout = fopen(oututFileName, "wb+");
if(NULL == pFout)
{
printf("open [%s],fail \n", oututFileName);
return -1;
}
printf("open [%s],OK\n", oututFileName);
return 0;
}
static void write_out_yuv_frame(AVFrame *frame)
{
int *pStride = frame->linesize;
int i;
for( i= 0; i < 3; i++ )
{
int nWidth = i == 0 ? frame->width : frame->width/2;
int nHeight = i == 0 ? frame->height : frame->height/2;
int y;
for(y = 0; y < nHeight; y++)
{
fwrite(frame->data[i], 1, nWidth, pFout);
frame->data[i] += pStride[i];
}
fflush(pFout);
}
}
int main(int argc, char **argv)
{
uint8_t inbuf[INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];
unsigned int uDataSize = 0;
int got_frame = 0;
uint8_t *pDataPtr = NULL;
uint8_t len = 0;
if(init(argc, argv) != 0)
{
printf("init err \n");
return -1;
}
printf("init OK\n");
if(open_codec() != 0)
{
printf("open_codec err \n");
return -1;
}
printf("open_codec OK\n");
while(1)
{
memset(inbuf, 0, AV_INPUT_BUFFER_PADDING_SIZE + INBUF_SIZE);
uDataSize = fread(inbuf, 1, INBUF_SIZE, pFin);
printf("read size=[%d] ----------------------------------- \n", uDataSize);
if(uDataSize == 0)
{
printf("break while\n");
break;
}
pDataPtr = inbuf;
while(uDataSize > 0)
{
printf("into while uDataSize=[%d]\n", uDataSize);
//int av_parser_parse2(AVCodecParserContext *s,
// AVCodecContext *avctx,
// uint8_t **poutbuf, int *poutbuf_size,
// const uint8_t *buf, int buf_size,
// int64_t pts, int64_t dts,
// int64_t pos);
len = av_parser_parse2(pCodecParserContext,
pCodecContext,
&pkt.data, &pkt.size,
pDataPtr, uDataSize,
AV_NOPTS_VALUE,
AV_NOPTS_VALUE,
AV_NOPTS_VALUE);
printf("av_parser_parse2 len=[%d]\n", len);
pDataPtr += len;
uDataSize -= len;
if(pkt.size != 0)
{
//成功的解析出一个包的数据
printf("Parser Packet! uDataSize=[%d]\n", uDataSize);
//int avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture,
// int *got_picture_ptr,
// const AVPacket *avpkt);
int ret = avcodec_decode_video2(pCodecContext, frame, &got_frame, &pkt);
printf("avcodec_decode_video2 return[%d]***************************\n", ret);
if(ret < 0)
{
printf("decode Err\n");
return -1;
}
if(got_frame)
{
printf("width*Height:[%d]*[%d]\n", frame->width, frame->height);
write_out_yuv_frame(frame);
}
}
else
{
printf(".");
continue;
}
}
}
pkt.data = NULL;
pkt.size = 0;
while(1)
{
int ret = avcodec_decode_video2(pCodecContext, frame, &got_frame, &pkt);
if(ret < 0)
{
printf("decode fial\n");
return -1;
}
if(got_frame)
{
printf("fflush width*Height:[%d]*[%d]", frame->width, frame->height);
write_out_yuv_frame(frame);
}
else
{
break;
}
}
finish();
printf("everything will be OK! \n");
return 0;
}
[root@localhost 03]#本文出自 “李春利” 博客,转载请与作者联系!
标签:03 ffmpeg 解码sdk调用 h264转yuv420
原文地址:http://990487026.blog.51cto.com/10133282/1975136