目录
ffmpeg
rk3588系列芯片
编程方法
最终的输出结果
ffmpeg示例程序
音视频处理中通常是用ffmpeg进行软件音视频编解码aac/h264编码,但其运行速度过慢消耗cpu占用率。因此需要寻找音视频硬件编解码方法。
自带音视频硬件编解码框架ffmedia或者mpp,其内部原理是配合内部硬件rga内存,把音视频数据读入内部rga内存中进行Mpp硬件编解码计算,包括h264编码输出编码裸流文件,并读入h264裸流文件,进行硬件解码并保存为mp4文件。
gitlab下载ffmedia_release,参考官方维基教程文档,下载并交叉编译参考例程。例程框架采用生产者消费者模式,一环一环前后配合,上一步的输出是下一步的输入,运行时只需启动第一步即可,第一步没有生产者。编码时需要先将图片数据读入rga中,再进行编码encmpp类调用。解码是调用media_decmpp类,解码后的数据可以通过调用回调函数setcallback()处理编码后输出数据。
可以写入mp4文件,或者通过rtsp流推出到服务器地址。同时ffmedia也支持从rtsp拉流,直接进行h264编码后保存本地或进行rtsp推流远端。
硬件编解码的代码可以参考上传资源。
#include
#include
#include
#include
#include
#include
#define WORD uint16_t
#define DWORD uint32_t
#define LONG int32_t
#pragma pack(2)
typedef struct tagBITMAPFILEHEADER {
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER, *PBITMAPFILEHEADER;
typedef struct tagBITMAPINFOHEADER {
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER, *PBITMAPINFOHEADER;
void saveBMP(struct SwsContext *img_convert_ctx, AVFrame *frame, int w, int h, char *filename)
{
//1 先进行转换, YUV420=>RGB24:
// int w = img_convert_ctx->frame_dst->width;
// int h = img_convert_ctx->frame_dst->height;
int data_size = w * h * 3;
AVFrame *pFrameRGB = av_frame_alloc();
//avpicture_fill((AVPicture *)pFrameRGB, buffer, AV_PIX_FMT_BGR24, w, h);
pFrameRGB->width = w;
pFrameRGB->height = h;
pFrameRGB->format = AV_PIX_FMT_BGR24;
av_frame_get_buffer(pFrameRGB, 0);
sws_scale(img_convert_ctx,
(const uint8_t* const *)frame->data,
frame->linesize,
0, frame->height, pFrameRGB->data, pFrameRGB->linesize);
//2 构造 BITMAPINFOHEADER
BITMAPINFOHEADER header;
header.biSize = sizeof(BITMAPINFOHEADER);
header.biWidth = w;
header.biHeight = h*(-1);
header.biBitCount = 24;
header.biCompression = 0;
header.biSizeImage = 0;
header.biClrImportant = 0;
header.biClrUsed = 0;
header.biXPelsPerMeter = 0;
header.biYPelsPerMeter = 0;
header.biPlanes = 1;
//3 构造文件头
BITMAPFILEHEADER bmpFileHeader = {0,};
//HANDLE hFile = NULL;
DWORD dwTotalWriten = 0;
DWORD dwWriten;
bmpFileHeader.bfType = 0x4d42; //'BM';
bmpFileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)+ data_size;
bmpFileHeader.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
FILE* pf = fopen(filename, "wb");
fwrite(&bmpFileHeader, sizeof(BITMAPFILEHEADER), 1, pf);
fwrite(&header, sizeof(BITMAPINFOHEADER), 1, pf);
fwrite(pFrameRGB->data[0], 1, data_size, pf);
fclose(pf);
//释放资源
//av_free(buffer);
av_freep(&pFrameRGB[0]);
av_free(pFrameRGB);
}
static void pgm_save(unsigned char *buf, int wrap, int xsize, int ysize,
char *filename)
{
FILE *f;
int i;
f = fopen(filename,"w");
fprintf(f, "P5\n%d %d\n%d\n", xsize, ysize, 255);
for (i = 0; i < ysize; i++)
fwrite(buf + i * wrap, 1, xsize, f);
fclose(f);
}
static int decode_write_frame(const char *outfilename, AVCodecContext *avctx,
struct SwsContext *img_convert_ctx, AVFrame *frame, AVPacket *pkt)
{
int ret = -1;
char buf[1024];
ret = avcodec_send_packet(avctx, pkt);
if (ret < 0) {
fprintf(stderr, "Error while decoding frame, %s(%d)\n", av_err2str(ret), ret);
return ret;
}
while (ret >= 0) {
fflush(stdout);
ret = avcodec_receive_frame(avctx, frame);
if(ret == AVERROR(EAGAIN) || ret == AVERROR_EOF){
return 0;
}else if( ret < 0){
return -1;
}
/* the picture is allocated by the decoder, no need to free it */
snprintf(buf, sizeof(buf), "%s-%d.bmp", outfilename, avctx->frame_number);
/*pgm_save(frame->data[0], frame->linesize[0],
frame->width, frame->height, buf);*/
saveBMP(img_convert_ctx, frame, 160, 120, buf);
}
return 0;
}
int main(int argc, char **argv)
{
int ret;
int idx;
const char *filename, *outfilename;
AVFormatContext *fmt_ctx = NULL;
const AVCodec *codec = NULL;
AVCodecContext *ctx = NULL;
AVStream *inStream = NULL;
AVFrame *frame = NULL;
AVPacket avpkt;
struct SwsContext *img_convert_ctx;
if (argc <= 2) {
fprintf(stderr, "Usage: %s