Ubuntu 14.04LTS FFmpeg H264解码实战

时间:2022-06-11
本文章向大家介绍Ubuntu 14.04LTS FFmpeg H264解码实战,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

安装FFmpeg

sudo add-apt-repository ppa:kirillshkrogalev/ffmpeg-next

sudo apt-get update

sudo apt-get install ffmpeg

sudo apt-get install libavcodec-ffmpeg-dev

解码过程

1. 包含头文件,C++中,需要extern "C"起来

extern "C"

{

#include <libavcodec/avcodec.h>

#include <libswscale/swscale.h> //如果不做图像处理时,不需要包含

#include <libavutil/imgutils.h> //如果不做图像处理时,不需要包含

};

2. 声明变量

AVCodec* codec;

AVCodecParserContext *parser;

AVCodecContext* context;

AVFrame* frame;

AVPacket* pkt;

//如果需要做图像处理,比如需要转换成位图,再声明两个变量。

SwsContext* img_convert_ctx; //图像处理上下文

AVFrame* rgb_frame; //转换后的图片数据

bool is_init_output_buffer = false;

3. 初始化

int Init()

{

avcodec_register_all();

pkt = av_packet_alloc();

codec = avcodec_find_decoder(AV_CODEC_ID_H264);

if (!codec) {

fprintf(stderr, "Codec not foundn");

return -1;

}

parser = av_parser_init(codec->id);

if (!parser) {

fprintf(stderr, "parser not foundn");

return -1;

}

context = avcodec_alloc_context3(codec);

if (!context) {

fprintf(stderr, "Could not allocate video codec contextn");

exit(1);

}

if (avcodec_open2(context, codec, NULL) < 0) {

fprintf(stderr, "Could not open codecn");

return -1;

}

frame = av_frame_alloc();

rgb_frame = av_frame_alloc();

if (!frame || !rgb_frame) {

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

return -1;

}

}

4. 解码

int decode(unsigned char* data, int data_size)

{

while (data_size > 0) {

int ret = av_parser_parse2(parser, context, &pkt->data, &pkt->size,

data, data_size, AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);

if (ret < 0) {

fprintf(stderr, "Error while parsingn");

return -1;

}

data += ret;

data_size -= ret;

if (pkt->size) {

ret = avcodec_send_packet(context, pkt);

if (ret < 0) {

fprintf(stderr, "Error sending a packet for decodingn");

return -1;

}

while (ret >= 0) {

ret = avcodec_receive_frame(context, frame);

if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)

break;

else if (ret < 0) {

fprintf(stderr, "Error during decodingn");

return -1;

}

//至此解码已经成功,下面进行YUV到RGB的转换

if (!is_init_output_buffer) {

//初试化转换后的图像数据buffer,只要初始化一次就行。

uint8_t *out_buffer = (unsigned char *)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_RGB24, context->width, context->height, 1));

av_image_fill_arrays(rgb_frame->data, rgb_frame->linesize, out_buffer, AV_PIX_FMT_RGB24, context->width, context->height, 1);

is_init_output_buffer = true;

}

//获取图像转换上下文

img_convert_ctx = sws_getCachedContext(img_convert_ctx, context->width, context->height,

context->pix_fmt, context->width, context->height, AV_PIX_FMT_RGB24,

SWS_X, NULL, NULL, NULL);

//图像转换

sws_scale(img_convert_ctx, frame->data, frame->linesize, 0, context->height, rgb_frame->data, rgb_frame->linesize);

//下面是3种数据的获取方式

//YUV数据

int y_size = context->width * context->height;

fwrite(rgb_frame->data[0], 1, y_size, fp_yuv); //Y

fwrite(rgb_frame->data[1], 1, y_size / 4, fp_yuv); //U

fwrite(rgb_frame->data[2], 1, y_size / 4, fp_yuv); //V

// RGB数据

fwrite(rgb_frame->data[0], (context->width) * (context->height) * 3, 1, fp);

// UYVY数据

//fwrite(rgb_frame->data[0], (context->width) * (context->height), 2, fp);

}

}

}

return 0;

}

5. 编译包含的库

LIBS += /usr/local/lib/libavcodec.a /usr/local/lib/libavutil.a /usr/local/lib/libswresample.a /usr/local/lib/libswscale.a -lz -ldl