最近接到的一个任务是,利用gstreamer1.0抓取framebuffer的fb0设备的RGB图像数据,进行h264编码,然后再转换为MP4视频;硬件平台式imx6qdl,内含IPU与VPU硬件,Linux内核版本是yocto project 4.1.15。
IPU:将RGB数据转为YUV格式,因为VPU只能接收YUV格式数据转换为H264
VPU:将YUV格式的数据转换为H264码流
关于gstreamer的概念,这里就不在详述,可以参考其开发手册与官网实例。尤其比较有用的工具是gst-inspect-1.0可以查看gstreamer所有的元件elements,或者gst-inspect-1.0 后跟元件名称,可以单独查看某一元件的详细信息。另外可以使用gst-lanuch-1.0工具,先进行测试,例如:
gst-launch-1.0ximagesrc remote=1 use-damage=0 ! video/x-raw,framerate=25/1 !videoconvert ! vp8enc ! matroskamux ! filesink location=/home/luke/test.mkv
可以实现在ubuntu16.04上进行录屏
根据应用需求,需要使用gstreamer1.0的appsrc、imxvideoconvert_ipu、vpuenc_h264、appsink、filesink、mp4mux共6个元件。现将RGB转为H264码,在PC上使用ffmpeg 工具进行转换测试;转换命令:ffmpeg -f h264 -i test_15x30.h264 -vcodec copy test_15x30.mp4代码如下:
#include <gst/gst.h>
#include <gst/app/gstappsrc.h>
#include <gst/app/gstappsink.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <signal.h>
typedef struct _GstDataStruct{
GstElement *pipeline;
GstElement *app_source;
GstElement *video_convert;
GstElement *auto_video_convert;
GstElement *h264_encoder;
GstElement *jpgenc;
GstElement *mp4mux;
GstElement *file_sink;
GstElement *app_sink;
guint sourceid; /* To control the GSource */
guint app_src_index;
guint app_sink_index;
GMainLoop *loop; /* GLib's Main Loop */
} GstDataStruct;
typedef struct
{
struct fb_var_screeninfo vinfo; // 可变的显示屏幕信息
int width; // width 宽度
int height; // height 高度
int bpp; // bit per pixel 像素的位数
int rowsize; // 屏幕一行所占字节数
int real_len; // 实际显示区域的字节数
int total_len; // 显示区域总字节数,即长度
int offset; // 实际显示位置在总长度中的偏移量
int fd; // 打开fb节点时的文件句柄
void* data; // fb0 节点内存映射后数据指针
}FbInfoStruct;
static void new_h264_sample_on_appsink (GstElement *sink, GstDataStruct *pGstData);
static void eos_on_appsink (GstElement *sink, GstDataStruct *pGstData);
static gboolean read_data(GstDataStruct *pGstData);
static void start_feed (GstElement * pipeline, guint size, GstDataStruct *pGstData);
static void stop_feed (GstElement * pipeline, GstDataStruct *pGstData);
gboolean bus_msg_call(GstBus *bus, GstMessage *msg, GstDataStruct *pGstData);
static FILE *fp; // 打开或保存文件的的指针
static GstBus *bus;
static GstDataStruct GstData;
static FbInfoStruct FbInfo;
int main(int argc, char *argv[])
{
guint bus_watch_id;
char file_name[32];
int frame_rate = 10;
int gop_size = 30;
if(argc == 3)
{
frame_rate = atoi(argv[1]);
gop_size = atoi(argv[2]);
}
memset (file_name, 0, sizeof(file_name));
sprintf(file_name, "%s", "/home/root/test_");
file_name[16] = frame_rate/10 + 0x30;
file_name[17] = frame_rate%10 + 0x30;
file_name[18] = 'x';
file_name[19] = gop_size/10 + 0x30;
file_name[20] = gop_size%10 + 0x30;
file_name[21] = '.';
file_name[22] = 'h';
file_name[23] = '2';
file_name[24] = '6';
file_name[25] = '4';
printf("file name is :%s\n", file_name);
printf("frame_rate:%d gop-size:%d\n", frame_rate, gop_size);
fp = fopen(file_name, "wb");
if(!fp)
{
printf("can not open file %s", file_name);
return -1;
}
printf("================ imx60 360 main start ==============\n");
memset (&GstData, 0, sizeof (GstDataStruct));
memset (&FbInfo, 0, sizeof (FbInfoStruct));
printf("=========== imx60 360 get fb0 info start ===========\n");
FbInfo.fd = open("/dev/fb0", O_RDWR);
ioctl(FbInfo.fd, FBIOGET_VSCREENINFO, &FbInfo.vinfo);
FbInfo.width = FbInfo.vinfo.xres;
FbInfo.height = FbInfo.vinfo.yres;
FbInfo.bpp = FbInfo.vinfo.bits_per_pixel;
FbInfo.rowsize = FbInfo.width * (FbInfo.bpp >> 3);
FbInfo.offset = FbInfo.rowsize * FbInfo.vinfo.yoffset;
FbInfo.total_len = FbInfo.vinfo.xres_virtual * FbInfo.vinfo.yres_virtual * (FbInfo.bpp >> 3);
FbInfo.real_len = FbInfo.width * FbInfo.height * (FbInfo.bpp >> 3);
FbInfo.data = mmap (NULL, FbInfo.total_len, PROT_READ | PROT_WRITE, MAP_SHARED, FbInfo.fd, 0);
printf("================= var screen info =================\n");
printf(" sz [%d x %d] %d\n", FbInfo.width, FbInfo.height, FbInfo.bpp);
printf(" vsz [%d x %d]\n", FbInfo.vinfo.xres_virtual, FbInfo.vinfo.yres_virtual);
printf(" pan : (%d, %d)\n", FbInfo.vinfo.xoffset, FbInfo.vinfo.yoffset);
printf(" off : %d\n", FbInfo.offset);
printf(" map : %p\n", FbInfo.data);
printf("============ imx60 360 get fb0 info end ===========\n");
/* Initialize cumstom data structure