封装成一个类
ffmpeg 库是4.1
FFmpegDecodeH264.h
#pragma once
// 此类设计输入H264码流,输出BGR buffer 数据
#include <stdio.h>
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
}
class ImageMat
{
public:
ImageMat()
{
}
~ImageMat()
{
if (data)
{
delete data;
}
}
int Create(int width, int height, int channel)
{
if (width * height * channel > this->width * this->height * this->channel)
{
if (this->data)
{
delete this->data;
this->data = new unsigned char[width * height * channel];
}
else
{
this->data = new unsigned char[width * height * channel];
}
}
this->width = width;
this->height = height;
this->channel = channel;
return 0;
}
int width = 0;
int height = 0;
int channel = 0;
unsigned char * data = NULL;
};
class FFmpegDecodeH264
{
public:
FFmpegDecodeH264();
~FFmpegDecodeH264();
// ImageMat 最后一个参数最好传入一个vector<ImageMat > 因为有时候传入一帧会输出多帧,此处如果输出多帧,只取最后一帧,可以自己改善
int InputH264Data(unsigned char * inputData, int inputLen, ImageMat &mImageMat); // 返回值0 有输出, 返回值<0 没有输出数据,刷新数据时候inputLen = 0;
private:
int decode(AVPacket *mpkt, ImageMat &mImageMat);
const AVCodec *codec;
AVCodecParserContext *parser = NULL;
AVCodecContext *c = NULL;
AVFrame *frame;
AVPacket *pkt;
struct SwsContext * sws_ctx = NULL;
};
FFmpegDecodeH264.cpp
#include "FFmpegDecodeH264.h"
//#include "opencv2/opencv.hpp"
FFmpegDecodeH264::FFmpegDecodeH264()
{
avcodec_register_all();
pkt = av_packet_alloc();
if (!pkt)
exit(1);
/* find the MPEG-1 video decoder */
codec = avcodec_find_decoder(AV_CODEC_ID_H264);
if (!codec) {
fprintf(stderr, "Codec not found\n");
exit(1);
}
c = avcodec_alloc_context3(codec);
if (!c) {
fprintf(stderr, "Could not allocate video codec context\n");
exit(1);
}
parser = av_parser_init(codec->id);
if (!parser) {
fprintf(stderr, "parser not found\n");
exit(1);
}
/* open it */
if (avcodec_open2(c, codec, NULL) < 0) {
fprintf(stderr, "Could not open codec\n");
exit(1);
}
frame = av_frame_alloc();
if (!frame) {
fprintf(stderr, "Could not allocate video frame\n");
exit(1);
}
}
FFmpegDecodeH264::~FFmpegDecodeH264()
{
av_parser_close(parser);
avcodec_free_context(&c);
av_frame_free(&frame);
av_packet_free(&pkt);
}
int FFmpegDecodeH264::InputH264Data(unsigned char * inputData, int inputLen, ImageMat & mImageMat)
{
int ret = 0;
int error = -1;
if (inputData == NULL)
{
decode(NULL, mImageMat);
}
while (inputLen >0) {
ret = av_parser_parse2(parser, c, &pkt->data, &pkt->size,
inputData, inputLen, AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);
if (ret < 0) {
fprintf(stderr, "Error while parsing\n");
exit(1);
}
inputData += ret;
inputLen -= ret;
if (pkt->size) {
int t_w = 0;
int t_h = 0;
error = decode(pkt, mImageMat);
printf("size = %d .....frame.width = %d frame.height = %d frame=%p frame.widthp=%d frame.heightp=%d \n",
pkt->size, frame->width, frame->height, frame, &frame->width, &frame->height);
}
}
return error;
}
int FFmpegDecodeH264::decode(AVPacket *mpkt, ImageMat & mImageMat)
{
int ret;
ret = avcodec_send_packet(c, mpkt);
if (ret < 0) {
fprintf(stderr, "Error sending a packet for decoding\n");
exit(1);
}
while (ret >= 0) {
ret = avcodec_receive_frame(c, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
return 0;
else if (ret < 0) {
fprintf(stderr, "Error during decoding\n");
exit(1);
}
printf("saving frame %3d\n", c->frame_number);
fflush(stdout);
/* the picture is allocated by the decoder. no need to
free it */
//snprintf(buf, sizeof(buf), "%s-%d", filename, c->frame_number);
//pgm_save(frame->data[0], frame->linesize[0],
// frame->width, frame->height, buf);
printf("frame->width = %d frame->height = %d frame=%p frame->width_p = %d frame->height_p = %d \n", frame->width, frame->height, frame, &frame->width, &frame->height);
AVPixelFormat src_pix_fmt = AV_PIX_FMT_YUV420P;
AVPixelFormat dst_pix_fmt = AV_PIX_FMT_BGR24;
sws_ctx = sws_getCachedContext(sws_ctx, frame->width, frame->height, src_pix_fmt,
frame->width, frame->height, dst_pix_fmt,
SWS_BILINEAR, NULL, NULL, NULL);
if (frame->height > 0)
{
mImageMat.Create(frame->width, frame->height, 3);
//cv::Mat mBGR = cv::Mat(frame->height, frame->width, CV_8UC3);
uint8_t *datas[2] = { 0 };
datas[0] = mImageMat.data;
int lines[2] = { 0 };
//lines[0] = frame->width * 3;
lines[0] = frame->width * 3;
int ret = sws_scale(sws_ctx,
frame->data, //输入数据
frame->linesize, //输入行大小
0,
frame->height, //输入高度
datas, //输出数据和大小
lines
);
#if 0
if (ret == frame->height)
{
cv::Mat mBGR = cv::Mat(frame->height, frame->width, CV_8UC3);
memcpy(mBGR.data, datas[0], frame->width * frame->height * 3);
cv::imshow("xxxx", mBGR);
cv::waitKey(40);
}
#endif
}
}
return 0;
}
main.cpp
#pragma comment(lib, "opencv_world300.lib")
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "opencv2/opencv.hpp"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
}
#include "FFmpegDecodeH264.h"
int main(int argc, char **argv)
{
const char *filename, *outfilename;
FILE *f;
uint8_t inbuf[4096 + AV_INPUT_BUFFER_PADDING_SIZE];
int ret;
int data_size;
if (argc <= 2) {
fprintf(stderr, "Usage: %s <input file> <output file>\n", argv[0]);
exit(0);
}
filename = "ds.264"; // 输入的264文件
outfilename = "";
/* set end of buffer to 0 (this ensures that no overreading happens for damaged MPEG streams) */
memset(inbuf + 4096, 0, AV_INPUT_BUFFER_PADDING_SIZE);
FFmpegDecodeH264 mFFmpegDecodeH264;
ImageMat mImageMat;
f = fopen(filename, "rb");
if (!f) {
fprintf(stderr, "Could not open %s\n", filename);
exit(1);
}
while (!feof(f)) {
/* read raw data from the input file */
data_size = fread(inbuf, 1, 4096, f);
if (!data_size)
break;
int retC = mFFmpegDecodeH264.InputH264Data(inbuf, data_size, mImageMat);
printf("####################mImge.height = %d ........\n", mImageMat.height);
if (mImageMat.height > 0)
{
cv::Mat imageShow = cv::Mat(mImageMat.height, mImageMat.width, CV_8UC3, mImageMat.data);
cv::imshow("last.", imageShow);
cv::waitKey(30);
}
}
/* flush the decoder */
int t_w = 0;
int t_h = 0;
//decode(c, frame, NULL, outfilename, mImageMat);
mFFmpegDecodeH264.InputH264Data(NULL, 0, mImageMat);
fclose(f);
return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)