将 h264 格式转换为YUV数据
废话少说,直接贴上代码。
decode_yuv.c
/*
* =====================================================================================
*
* Filename: decode_yuv.c
*
* Description:
*
* Version: 1.0
* Created: 11/15/17 15:26:12
* Revision: none
* Compiler: gcc
*
* Author: linsheng.pan (), life_is_legend@163.com
* Organization:
*
* =====================================================================================
*/
#include <stdlib.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libavutil/imgutils.h>
void usage(void)
{
printf("decode_yuv input_file output_file.yuv\n");
}
int main(int argc, char *argv[])
{
if(argc != 3)
{
usage();
return -1;
}
char *input_file = argv[1];
char *output_file = argv[2];
AVFormatContext *pFormatCtx = NULL;
AVCodecContext *pCodecCtx = NULL;
AVCodec *pCodec = NULL;
AVFrame *pFrameYUV = NULL;
AVFrame *pFrame = NULL;
AVPacket *packet = NULL;
uint32_t i = 0;
int videoindex = -1;
int y_size = -1;
int ret = 0;
int got_picture = 0;
uint8_t *out_buffer = NULL;
struct SwsContext *img_convert_ctx = NULL;
FILE *fp = fopen(output_file, "wb+");
av_register_all();
avformat_network_init();
pFormatCtx = avformat_alloc_context();
if(!pFormatCtx)
{
printf("Error: call avformat_alloc_context failed!");
return -1;
}
//打开视频文件
if(0 != avformat_open_input(&pFormatCtx, input_file, NULL, NULL))
{
printf("Error: call avformat_open_input failed!\n");
return -1;
}
//获取视频信息
if(avformat_find_stream_info(pFormatCtx, NULL) < 0)
{
printf("Error: call avformat_find_stream_info failed!\n");
return -1;
}
//查找解码器
videoindex = -1;
for(i = 0; i < pFormatCtx->nb_streams; ++i)
{
if(AVMEDIA_TYPE_VIDEO == pFormatCtx->streams[i]->codec->codec_type)
{
videoindex = i;
break;
}
}
if(-1 == videoindex)
{
printf("Error: can't find a video stream!\n");
return -1;
}
pCodecCtx = pFormatCtx->streams[videoindex]->codec;
pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
if(!pCodec)
{
printf("Error: Codec not find!\n");
return -1;
}
//打开解码器
if(avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
{
printf("Error: Can't open codec!\n");
return -1;
}
printf("width = %d\n", pCodecCtx->width);
printf("height = %d\n", pCodecCtx->height);
//将pFrameYUV 和 out_buffer 关联上
pFrame = av_frame_alloc();
pFrameYUV = av_frame_alloc();
out_buffer = (uint8_t *)av_malloc(avpicture_get_size(AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height));
avpicture_fill((AVPicture *)pFrameYUV, out_buffer, AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);
packet = (AVPacket *)av_malloc(sizeof(AVPacket));
av_init_packet(packet);
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);
//打印文件信息
printf("#------------------------------#\n");
av_dump_format(pFormatCtx, 0, input_file, 0);
printf("#------------------------------#\n");
while(av_read_frame(pFormatCtx, packet) >= 0)
{
if(videoindex == packet->stream_index)
{
ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);
if(ret < 0)
{
printf("Error: Decode failed!\n");
return -1;
}
if(got_picture)
{
sws_scale(img_convert_ctx, (uint8_t *)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize);
y_size = pCodecCtx->width * pCodecCtx->height;
fwrite(pFrameYUV->data[0], 1, y_size, fp);
fwrite(pFrameYUV->data[1], 1, y_size/4, fp);
fwrite(pFrameYUV->data[2], 1, y_size/4, fp);
printf("Succeed to decode 1 Frame!\n");
}
}
av_free_packet(packet);
}
//flush decoder
//当av_read_frame 退出循环的时候,实际上解码器中可能还包含
//剩余的几帧数据。直接调用avcodec_decode_video2获得AVFrame ,
//而不再向解码器传递AVPacket
while(1)
{
ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);
if(ret < 0)
{
break;
}
if(!got_picture)
{
break;
}
sws_scale(img_convert_ctx, (uint8_t *)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize);
y_size = pCodecCtx->width * pCodecCtx->height;
fwrite(pFrameYUV->data[0], 1, y_size, fp);
fwrite(pFrameYUV->data[1], 1, y_size/4, fp);
fwrite(pFrameYUV->data[2], 1, y_size/4, fp);
printf("Succeed to decode 1 Frame!\n");
}
sws_freeContext(img_convert_ctx);
fclose(fp);
av_frame_free(&pFrame);
av_frame_free(&pFrameYUV);
avcodec_close(pCodecCtx);
avformat_close_input(&pFormatCtx);
return 0;
}
编译:gcc decode_yuv.c -o decode_yuv -lavformat -lavcodec -lavutil -lswscale