Linux下:Live555+S5pV210的mfc模块硬解方案实现

本文介绍Live555作为rtsp客户端,s5pv210做媒体终端,硬解码得Nv12图像序列。

mplayer 播放yuv命令:

mplayer -demuxer rawvideo -rawvideo w=700:h=480 /sdcard/Resource/Img_700_480.yuv

编码:

1)还是和编码一样superboot,必不可少,u-boot不行

2)调用SsbSipMfcDecInit()之前一定要先调用SsbSipMfcDecGetInBuf()然后填入header(SPS/PPS/SEI)信息。

3)SsbSipMfcDecGetOutBuf()返回的status只有是MFC_GETOUTBUF_DISPLAY_DECODING或者MFC_GETOUTBUF_DISPLAY_ONLY时YVirAddr和CVirAddr才有效,如果返回MFC_GETOUTBUF_DECODING_ONLY则需要再次调用SsbSipMfcDecExe()和SsbSipMfcDecGetOutBuf()

4)YVirAddr和CVirAddr指向的数据是tiled nv12的格式(64x32 tiled),需要转化成现行格式才能正常现实。这个mfc api已经提供了csc_tiled_to_linear(),头文件color_space_convertor.h

5)测试程序有几个问题:不支持multi-slice的帧;最后buffer里的几帧偷懒没有处理直接丢掉了;如果第一个header后的数据帧不是IDR的话,会出warning,直到第一个IDR帧为止,之前的non-IDR帧可能译码不正确或者丢帧。

下图是函数流程

而Live555的嵌入过程如下:

关键流程如下函数所示:

int H264Decoder_c::SsbSipMfcDecode264Stream(char* frame,int framelen)
{
	char* ImgPtr = NULL ; int tmp_width=-1 ; int tmp_height = -1 ;
	ImgPtr = SsbSipMfcUsrDecodeAFrame(frame,framelen,m_SsbSipMfc_virbuf,m_SsbSipMfc_openHandle,&tmp_width,&tmp_height);
	if(ImgPtr!=NULL){
		u_int8_t* src[3] ;
		int linesize[3] ;

		src[0] = (u_int8_t*)ImgPtr ;  src[1] = src[0] + tmp_width*tmp_height ; src[2] = src[1] + tmp_width*tmp_height/4 ;
		linesize[0] = tmp_width ; linesize[1] = tmp_width/2 ; linesize[2] = linesize[1];
		ScaleYUVImgToRGB(tmp_width,tmp_height,src,linesize,tmp_width,tmp_height) ;

		CallImgPaint(g_cenptr,tmp_width,tmp_height);
		free(ImgPtr);
	}
	return framelen ;
}
int SsbSipMfcUsrOpenMfcDecodeModule(char *spspps,int spsppslen,void **openHandle,void **virInBuf)
{
	int i=0 ; int set_conf_val ;
	void * phyInBuf;
	SSBSIP_MFC_ERROR_CODE err;
	//unsigned int buf_type = CACHE;
	unsigned int buf_type = CACHE;

    *openHandle = SsbSipMfcDecOpen(&buf_type);
    if(!*openHandle) {
        fprintf(stderr,"Error: SsbSipMfcDecOpen.\n");
        return -1 ;
    }
    printf("SsbSipMfcDecOpen succeeded.\n");

    *virInBuf = SsbSipMfcDecGetInBuf(*openHandle, &phyInBuf, MAX_DECODER_INPUT_BUFFER_SIZE);
    // MAX_DECODER_INPUT_BUFFER_SIZE was defined in SsbSipMfcApi.h, = 1024*3072 = 3 MiB
    if(!*virInBuf) {
        fprintf(stderr,"Error: SsbSipMfcDecGetInBuf.\n");
        return -1 ;
    }
    printf("SsbSipMfcDecGetInBuf succeeded.\n");

#if 1 // this might improve performance. to be confirmed
    set_conf_val = 3;
    SsbSipMfcDecSetConfig(openHandle, MFC_DEC_SETCONF_EXTRA_BUFFER_NUM, &set_conf_val);

    set_conf_val = 4;
    SsbSipMfcDecSetConfig(openHandle, MFC_DEC_SETCONF_DISPLAY_DELAY, &set_conf_val);
#endif

    memcpy(*virInBuf,spspps,spsppslen);

#if 1
    printf("Header: ");
    for(i=0;i<spsppslen;i++)
        printf("%x ",((uint8_t*)(*virInBuf))[i]);
    printf("\n");
#endif

    err = SsbSipMfcDecInit(*openHandle,H264_DEC,spsppslen);
    if(err<0) {
        fprintf(stderr,"Error: SsbSipMfcDecInit. Code %d\n",err);
        printf("Error: SsbSipMfcDecInit. Code %d\n",err);
        return -1 ;
    }
    printf("SsbSipMfcDecInit succeeded.\n");

    return 0 ;
}
void SsbSipMfcUsrShowStatus(SSBSIP_MFC_DEC_OUTPUT_INFO *oinfo,SSBSIP_MFC_DEC_OUTBUF_STATUS status)
{
    printf("Status: ");
    switch (status) {
        case MFC_GETOUTBUF_DECODING_ONLY:
            printf("Decoding Only\n");
            break;
        case MFC_GETOUTBUF_DISPLAY_DECODING:
            printf("Display and Decoding\n");
            break;
        case MFC_GETOUTBUF_DISPLAY_ONLY:
            printf("Display Only\n");
            break;
        case MFC_GETOUTBUF_DISPLAY_END:
            printf("DPB is empty\n");
            break;
        default:
            printf("Unknown Status!\n");
            break;
    }
    printf("img_width=%d, img_height=%d\n",oinfo->img_width,oinfo->img_height);
    printf("YVirAddr=%x, CVirAddr=%x\n",oinfo->YVirAddr,oinfo->CVirAddr);
    printf("buf_width=%d, buf_height=%d\n",oinfo->buf_width,oinfo->buf_height);
    printf("consumedByte=%d\n",oinfo->consumedByte);
}
char* SsbSipMfcUsrNV12Dump(SSBSIP_MFC_DEC_OUTPUT_INFO *oinfo,SSBSIP_MFC_DEC_OUTBUF_STATUS status,int *width,int *height)
{
	static int channel=1 ; int i=0 ;
	if(status==MFC_GETOUTBUF_DISPLAY_DECODING || status==MFC_GETOUTBUF_DISPLAY_ONLY)
	{
		char *NV12=NULL ;
		NV12=malloc((int)(oinfo->img_width*oinfo->img_height*1.5));
		if(!NV12) {
			fprintf(stderr,"Out of memory.\n");
		}

		// converted tiled to linear nv12 format - Y plane
		csc_tiled_to_linear(NV12,oinfo->YVirAddr,oinfo->img_width,oinfo->img_height);
		// converted tiled to linear nv12 format - C plane
		csc_tiled_to_linear(NV12+oinfo->img_width*oinfo->img_height,oinfo->CVirAddr,oinfo->img_width,oinfo->img_height/2);
		SsbSipMfcUsrNV12ToYV12(NV12,oinfo->img_width,oinfo->img_height);
		*width=oinfo->img_width; *height=oinfo->img_height;

		//Fprintf_Binary("SsbSipMfcYUV.yuv",NV12,(int)(oinfo->img_width*oinfo->img_height*1.5),"ab");
		//free(NV12);
		return NV12 ;

	}
	return NULL ;
}
char* SsbSipMfcUsrDecodeAFrame(char *framebuf,int framelen,void *virInBuf,void *openHandle,int *width,int *height)
{
	static int cnt=0 ;
	void *phyInBuf ;
	SSBSIP_MFC_ERROR_CODE err;
	SSBSIP_MFC_DEC_OUTPUT_INFO oinfo;
	SSBSIP_MFC_DEC_OUTBUF_STATUS status;
	char* ImgPtr=NULL ;

	status = MFC_GETOUTBUF_STATUS_NULL;
	//printf("length:%d\n",SsbSipMfcUsrReadOneFrame(&framebuf,framelen));

    memcpy(virInBuf,framebuf,framelen);

s5pv210_decode:   // take care of goto ,use as less as possible

    err = SsbSipMfcDecExe(openHandle, framelen);
    if(err<0) {
    	fprintf(stderr,"Error: SsbSipMfcDecExe. Code %d\n",err);
    	return -1 ;
    }
    else{
//    	printf("SsbSipMfc Decode OK frame %d !!\n",cnt++);
    	if(cnt>10000)
    		cnt=0 ;
    }

    memset(&oinfo,0,sizeof(oinfo));
    status = SsbSipMfcDecGetOutBuf(openHandle,&oinfo);

    if(status==MFC_GETOUTBUF_DECODING_ONLY){
    	printf("decode not done redecode\n");
    	goto s5pv210_decode ;
    }
    else if((status==MFC_GETOUTBUF_DISPLAY_DECODING) ||(status==MFC_GETOUTBUF_DISPLAY_ONLY))
    {
    	static int cnt =0 ;
    	if((cnt++)%2){
    		if(cnt>1000)
    			cnt = 0 ;
    		return NULL ;
    	}
    	//SsbSipMfcUsrShowStatus(&oinfo,status);
		ImgPtr = SsbSipMfcUsrNV12Dump(&oinfo,status,width ,height);
		return ImgPtr ;
    }
    else{
    	printf("s5pv210 decode unexpected status goto decode again\n");
    	goto s5pv210_decode ;
    }

    return NULL ;
}

同时,函数中的调用,经过优化,只需要两步,open->decode完事。

参考文章:

Android S5PV210 fimc驱动分析 - fimc_regs.c

http://blog.csdn.net/mirkerson/article/details/8192600

s5pv210中MFC的编码过程

http://blog.csdn.net/mirkerson/article/details/8953469

s5pv210 mfc子解码

http://bbs.csdn.net/topics/390385062

s5pv210 HDMI 显示实现

http://blog.csdn.net/liujia2100/article/details/21788667

NV12转RGB

http://www.armbbs.net/forum.php?mod=viewthread&tid=18938

【成功】tiny210在Linux下的MFC库移植及硬编码测试源码

http://www.arm9home.net/read.php?tid-28647.html

【这次是解码】tiny210在Linux下的MFC库移植及硬解码测试源码

http://www.arm9home.net/read.php?tid-28822.html

 TQ210
linux下NV12T转RGB显示问题

http://www.armbbs.net/forum.php?mod=viewthread&tid=18938

时间: 2024-12-10 08:47:13

Linux下:Live555+S5pV210的mfc模块硬解方案实现的相关文章

Linux下的内核编译与模块操作

Linux下的内核编译与模块操作 一:实验环境 1):虚拟机 2):linux系统 3):linux系统的硬盘的空余空间要大于7G 4):虚拟机的内存要大于2.5G以上 二:实验目标 1):源码编译Linux内核 2):使用Linux内核模块 3):实战-编译一个NTFS内核模块,实现linux挂载NTFS文件系统并实现读写功能 三:实验脚本 第一块 --源码编译Linux内核 linux系统与windows系统是两种截然不同的系统,windows系统中的软件都是需要付费的,而linux系统中的

(转)LINUX下Live555不能获取ip地址解决方法

linux下运行live55 显 示如图 :没有获取ip:  ip是0.0.0.0 live555在不知道本地IP地址与网络接口的情况下,通过一个在本地某端口建立一个UDP连接,然后把这个UDP连接加入 到一个组播组 ,当然要对这个组播组进行相应的设置,比如TTL,回环等等:然后通过UDP连接发送一个数据:最后通过这个UDP连接接收这个数据,并且解析相应的发送地址:大概流程就是这样了. 具体的代码片段live555:groupsock/GroupsockHelper.cpp里:因此我们设置固定的

linux下PHP扩展安装memcache模块

linux下PHP扩展安装memcache模块   roid 安装环境RHEL 4Php 5.2.6 所需软件libevent-1.4.6-stable.tar.gz (http://monkey.org/~provos/libevent/)memcache-2.2.3.tgz (http://pecl.php.net/package/memcache)memcached-1.2.6.tar.gz (http://www.danga.com/memcached/) 安装配置 1. 安装libev

linux下创建和删除软、硬链接

参考:https://www.cnblogs.com/xiaochaohuashengmi/archive/2011/10/05/2199534.html linux下创建和删除软.硬链接 在Linux系统中,内核为每一个新创建的文件分配一个Inode(索引结点),每个文件都有一个惟一的inode号.文件属性保存在索引结点里,在访问文件时,索引结点被复制到内存在,从而实现文件的快速访问. 链接是一种在共享文件和访问它的用户的若干目录项之间建立联系的一种方法.Linux中包括两种链接:硬链接(Ha

Linux下同步工具inotify+rsync使用详解

Linux下同步工具inotify+rsync使用详解 Posted on 2014-12-12 |  In Linux|  9|  Visitors 438 1. rsync 1.1 什么是rsync rsync是一个远程数据同步工具,可通过LAN/WAN快速同步多台主机间的文件.它使用所谓的"Rsync演算法"来使本地和远程两个主机之间的文件达到同步,这个算法只传送两个文件的不同部分,而不是每次都整份传送,因此速度相当快.所以通常可以作为备份工具来使用. 运行Rsync serve

Linux下实现秒级定时任务的两种方案

Linux下实现秒级定时任务的两种方案(Crontab 每秒运行): 第一种方案,当然是写一个后台运行的脚本一直循环,然后每次循环sleep一段时间. while true ;do command sleep XX //间隔秒数 done 第二种方案,使用crontab. 我们都知道crontab的粒度最小是到分钟,但是我们还是可以通过变通的方法做到隔多少秒运行一次. 以下方法将每20秒执行一次 crontab -e * * * * * /bin/date* * * * * sleep 20;

Linux下创建和删除软、硬链接 可临时处理空间不足

在Linux系统中,内核为每一个新创建的文件分配一个Inode(索引结点),每个文件都有一个惟一的inode号.文件属性保存在索引结点里,在访问文件时,索引结点被复制到内存在,从而实现文件的快速访问. 链接是一种在共享文件和访问它的用户的若干目录项之间建立联系的一种方法.Linux中包括两种链接:硬链接(Hard Link)和软链接(Soft Link),软链接又称为符号链接(Symbolic link).符号连接相当于Windows下的快捷方式. 一.硬链接 硬链接说白了是一个指针,指向文件索

Linux下编译安装Apache及模块

Apache是使用非常广泛的web服务器,多平台支持,是时下最流行的Web服务器端软件之一.Apache快速.可靠,并且可通过简单的API扩充,就可以集成PHP/Python等语言解释器.文章这里讲解如何在linux下编译 Apache,以及如何编译Apache模块. linux下编译Apache 下载Apache源代码,编译过程如下: $ wget http://apache.fayea.com//httpd/httpd-2.4.12.tar.gz $ tar -zxf httpd-2.4.1

在linux下创建和删除软、硬链接

说明:在安装Mysql时,采用软链接的方式来访问Mysql安装包,这样可以避免后期升级,而且不方便知晓其版本,软链接和硬链接操作如下 来源地址:https://www.cnblogs.com/xiaochaohuashengmi/archive/2011/10/05/2199534.html在Linux系统中,内核为每一个新创建的文件分配一个Inode(索引结点),每个文件都有一个惟一的inode号.文件属性保存在索引结点里,在访问文件时,索引结点被复制到内存在,从而实现文件的快速访问. 链接是