免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 818 | 回复: 0

硬解 [复制链接]

论坛徽章:
0
发表于 2011-02-27 00:59 |显示全部楼层
S3C6410 MFC decode H.264流程(1)
2009-12-15 12:45

郁闷的,用MFC放出来的H.264视屏竟然是黑白的,无奈跟踪下MFC的调用流程:

内核启动初始化:
1)执行s3c_mfc_init(),打印“S3C6400 MFC Driver, (c) 2007 Samsung Electronics”;
2)注册平台设备platform_driver_register(&s3c_mfc_driver);
3)进入s3c_mfc_probe();
4)获取时钟、打开时钟,映射寄存器物理地址,获取中断、注册中断;
5)调用s3c_get_media_memory(S3C_MDEV_MFC),获取显存空间;
6)调用s3c_mfc_setup_memory(),设置Bitprocessor buffer, Data buffer;
7)调用s3c_mfc_memmap_databuf,打印以下信息“s3c_mfc_memmap_databuf: virtual address of data buffer = 0xc0700000”;
8)调用s3c_mfc_init_yuvbuf_mgr(),This function initializes the MfcFramBufMgr(Buffer Segment Manager);
最后打印“address of segment_info=c0bd6400, address of commit_info =c0be0040”
9)调用s3c_mfc_init_hw(),初始化硬件;
1. Reset the MFC IP
2. Download Firmware code into MFC
输出:“s3c_mfc_init_hw: downloading firmware into bitprocessor”;
3. Start Bit Processor
4. Set the Base Address Registers for the following 3 buffers(CODE_BUF, WORKING_BUF, PARAMETER_BUF)
5. Set the Control Registers
输出:
s3c_mfc_get_firmware_ver: GET_FW_VER command was issued
s3c_mfc_get_firmware_ver: GET_FW_VER => 0xf202, 0x130e
s3c_mfc_get_firmware_ver: BUSY_FLAG => 0

10)最后再次输出banner:S3C6400 MFC Driver, (c) 2007 Samsung Electronics。


H.264 decode时:
0)上层调用s3c_mfc_open();
1)调用s3c_mfc_init_yuvbuf_mgr();
2)调用s3c_mfc_yuv_buffer_mgr_final(),表示不需要重新分配yuv buffer;
3)调用s3c_mfc_init_hw(),重新初始化硬件;
4)调用s3c_mfc_inst_create创建一个实例->s3c_mfc_get_stream_buffer_addr()获取流地址;
输出:
s3c_mfc_get_stream_buffer_addr: ctx->stream_buffer address 0xc0700000
s3c_mfc_get_stream_buffer_addr: ctx->phys_addr_stream_buffer address 0x50700000
s3c_mfc_inst_create: state = 10 /* instance is created but not initialized */
5)输出s3c_mfc_open: mfc open success,open结束。

6)调用s3c_mfc_ioctl,发送命令: cmd = 80000f,S3C_MFC_IOCTL_MFC_GET_LINE_BUF_ADDR
copy_from_user
处理XXXXXX
copy_to_user
7)调用s3c_mfc_ioctl,发送命令: cmd = 800005,S3C_MFC_IOCTL_MFC_H264_DEC_INIT
copy_from_user
codec_mode = AVC_DEC;
Initialize MFC Instance
——>s3c_mfc_inst_init_dec
(1)checking state
(2)codec_mode
(3)stream size checking
(4)判断instance序列号
(5)s3c_mfc_set_eos(0);
(6)s3c_mfc_issue_command();
(7)s3c_mfc_stream_end();
(8)获取视屏参数
(9)s3c_mfc_get_yuv_buffer_addr——>s3c_mfc_print_commit_yuv_buffer_info();
(10)s3c_mfc_get_param_buff_virt_addr();
/*
* set the parameters in the parameters buffer for SET_FRAME_BUF command. 
* buffer address of y, cb, cr will be set in parameters buffer before issuing SET_FRAME_BUF command
*/
(11)s3c_mfc_issue_command(ctx->inst_no, ctx->codec_mode, SET_FRAME_BUF);
(12)changing state to 20;
输出信息:
s3c_mfc_inst_init_dec: strm_leng = 7767
s3c_mfc_inst_init_dec: ctx->inst_no = 0
s3c_mfc_inst_init_dec: ctx->codec_mode = 2
s3c_mfc_inst_init_dec: sequece bit buffer size = 500 (kb)
s3c_mfc_inst_init_dec: RET_DEC_SEQ_SRC_SIZE = 737680
s3c_mfc_inst_init_dec: RET_DEC_SEQ_SRC_FRAME_RATE   = 0
s3c_mfc_inst_init_dec: RET_DEC_SEQ_FRAME_NEED_COUNT = 3
s3c_mfc_inst_init_dec: RET_DEC_SEQ_FRAME_DELAY = 0
s3c_mfc_inst_init_dec: width = 720, height = 400, buf_width = 720, buf_height = 400
s3c_mfc_print_commit_yuv_buffer_info: commit index = 000, base segment index = 0
s3c_mfc_print_commit_yuv_buffer_info: commit index = 000, number of segment = 1325
s3c_mfc_get_yuv_buffer_addr: ctx->inst_no : 0
s3c_mfc_get_yuv_buffer_addr: ctx->yuv_buffer : 0xc07fa000
s3c_mfc_get_yuv_buffer_addr: ctx->phys_addr_yuv_buffer : 0x507fa000

回到ioctrl
将初始化信息copy_to_user

8)视屏播放过程中,反复调用
s3c_mfc_ioctl: cmd = 800007
s3c_mfc_ioctl: cmd = 800011

9)cmd = 800007,S3C_MFC_IOCTL_MFC_H264_DEC_EXE
copy_from_user从用户态获取数据,sizeof(s3c_mfc_enc_exe_arg_t)
s3c_mfc_inst_dec 对数据进行decode,真正decode函数,此函数需要重点关注
copy_to_user将数据返回用户态
难道直接将YUV数据返回用户?然后用户态再操作Framebuffer???

10)cmd = 800011,S3C_MFC_IOCTL_MFC_GET_YUV_BUF_ADDR
copy_from_user,sizeof(s3c_mfc_enc_exe_arg_t)
    yuv_size = (pMfcInst->buf_width * pMfcInst->buf_height * 3) >> 1;
    args.get_buf_addr.out_buf_size = yuv_size;

    in_usr_data = (unsigned int)args.get_buf_addr.in_usr_data;
    yuv_buffer = (unsigned int)pMfcInst->yuv_buffer;
    run_index = pMfcInst->run_index;
    out_buf_size = args.get_buf_addr.out_buf_size;
    databuf_vaddr = (unsigned int)s3c_mfc_get_databuf_virt_addr();
    offset = yuv_buffer + run_index * out_buf_size - databuf_vaddr;
copy_to_user

11)解码完毕,调用s3c_mfc_release释放instance
s3c_mfc_release: deleting instance number = 0

仅仅分析了调用过程,下一步需要研究解码过程这两个操作究竟是干什么的,有什么区别
cmd = 800007,S3C_MFC_IOCTL_MFC_H264_DEC_EXE
cmd = 800011,S3C_MFC_IOCTL_MFC_GET_YUV_BUF_ADDR

阿虚(Rockie Cheng)


上次写到吃中午饭,匆匆收笔,后来调wifi,竟然忘了。

趁周末,把这个坑填上。

cmd = 800007,S3C_MFC_IOCTL_MFC_H264_DEC_EXE

s3c_mfc_inst_dec 对数据进行decode

s3c_mfc_inst_dec函数分析
简介: this function decodes the input stream and put the decoded frame into the yuv buffer 
输入参数
s3c_mfc_inst_context_t *ctx 结构体包含instance number,stream buffer和yuv buffer
unsigned long strm_leng stream长度
1) checking state(忽略所有涉及到旋转的代码)
2)大部分情况下,根据inst_no选择对应的MFC物理端口(8个)
3)计算size:frm_size = ctx->buf_width * ctx->buf_height;
4)
/* DEC_PIC_OPTION was newly added for MP4ASP */
writel(0x7, s3c_mfc_sfr_base_virt_addr + S3C_MFC_PARAM_DEC_PIC_OPTION);
writel(ctx->mv_mbyte_addr, s3c_mfc_sfr_base_virt_addr + S3C_MFC_PARAM_DEC_PIC_MV_ADDR);
writel(ctx->mv_mbyte_addr + 25920, s3c_mfc_sfr_base_virt_addr + S3C_MFC_PARAM_DEC_PIC_MBTYPE_ADDR);
这段代码中的寄存器我的数据手册里面竟然没有,看来应该更新了

5)将stream物理地址写入CMD_DEC_PIC_BB_START (0x1AC)
需要4byte对齐
4-byte aligned byte address of the decoder input picture stream buffer

6)不对齐的数据写入CMD_DEC_PIC_START_BYTE (0x1B0)
Byte Address of valid bitstream in input picture stream buffer

7)将stream length写入CMD_DEC_PIC_CHUNK_SIZE (0x1A8)
Byte size of picture stream data

8)s3c_mfc_issue_command(ctx->inst_no, ctx->codec_mode, PIC_RUN)
启动解码函数
根据S3C_MFC_IOCTL_MFC_H264_DEC_INIT的配置,codec_mode应该为2

将inst_no写入RunIndex (0x168)
将codec_mode = 2写入RunCodStd (0x16C)
将run命令写入RunCommand (0x164),启动解码
挂起interruptible_sleep_on_timeout(&s3c_mfc_wait_queue, 500)

9)读取命令执行结果状态寄存器RET_DEC_PIC_SUCCESS (0x1D8)

10)读取RET_DEC_PIC_IDX (0x1C4)
Display frame index
After BIT decodes one frame, BIT return display frame index to this register.
并判断帧情况,是否结尾,是否失败等等

11)转换inst_no的状态
//* changing state 
//* state change to S3C_MFC_INST_STATE_DEC_PIC_RUN_LINE_BUF
S3C_MFC_INST_STATE_TRANSITION(ctx, S3C_MFC_INST_STATE_DEC_PIC_RUN_LINE_BUF);

12)返回OK


===========================================================================

IOCTRL:cmd = 800011,S3C_MFC_IOCTL_MFC_GET_YUV_BUF_ADDR       

DEC部分分析,这一段并没有涉及到解码,解码主要在上面完成


   out = copy_from_user(&args.get_buf_addr, 
    (s3c_mfc_get_buf_addr_arg_t *)arg, 
    sizeof(s3c_mfc_get_buf_addr_arg_t));

   if (pMfcInst->yuv_buffer == NULL) {
    mfc_err("mfc frame buffer is not internally allocated yet\n");
    mutex_unlock(s3c_mfc_mutex);
    return -EFAULT;
   }

   /* FRAM_BUF address is calculated differently for Encoder and Decoder. */
   switch (pMfcInst->codec_mode) {
   case MP4_DEC:
   case AVC_DEC:
   case VC1_DEC:
   case H263_DEC:
    /* Decoder case */
    yuv_size = (pMfcInst->buf_width * pMfcInst->buf_height * 3) >> 1; //计算YUV的大小
    args.get_buf_addr.out_buf_size = yuv_size;//填充out_buf_size尺寸

    in_usr_data = (unsigned int)args.get_buf_addr.in_usr_data;
    yuv_buffer = (unsigned int)pMfcInst->yuv_buffer;
    run_index = pMfcInst->run_index;
    out_buf_size = args.get_buf_addr.out_buf_size;
    databuf_vaddr = (unsigned int)s3c_mfc_get_databuf_virt_addr();
    offset = yuv_buffer + run_index * out_buf_size - databuf_vaddr;//计算偏移量
   
    args.get_buf_addr.out_buf_addr = in_usr_data + offset;//填充out_buf地址
    break;

   } /* end of switch (codec_mode) */

   args.get_buf_addr.ret_code = S3C_MFC_INST_RET_OK;
   out = copy_to_user((s3c_mfc_get_buf_addr_arg_t *)arg, &args.get_buf_addr, sizeof(s3c_mfc_get_buf_addr_arg_t));

   break;

阿虚(Rockie Cheng)


今天用三星的测试程序跑了一下H.264,发现颜色正常,打印出的信息有所不同。
covia android解码时的ioctrl命令为
s3c_mfc_ioctl: cmd = 800007
s3c_mfc_ioctl: cmd = 800011

测试程序解码为
s3c_mfc_ioctl: cmd = 800007
s3c_mfc_ioctl: cmd = 800013

前面分析过s3c_mfc_ioctl: cmd = 800011是将YUV数据返回用户
而s3c_mfc_ioctl: cmd = 800013和前者不一样的地方在于:
1)databuf_paddr = (unsigned int)S3C_MFC_BASEADDR_DATA_BUF;
//直接用寄存器(Physical Base Address for the MFC Data Buffer )地址填充
2)args.get_buf_addr.out_buf_addr = databuf_paddr + offset;
//输出地址用paddr填充,databuf_paddr

分析:
MFC转换出的数据格式是YUV的。
三星的测试程序使用了Post Processor驱动,800013命令返回物理地址给pp使用,直接刷到fb上。
推测covia的驱动可能没有使用pp,而是手动做的YUV2RGB再刷到fb,仅仅是推测,因为q5的内核也含有pp驱动。


附录:一些代码及调试信息
case S3C_MFC_IOCTL_MFC_GET_PHY_FRAM_BUF_ADDR:
   mutex_lock(s3c_mfc_mutex);

   out = copy_from_user(&args.get_buf_addr, 
    (s3c_mfc_get_buf_addr_arg_t *)arg, 
    sizeof(s3c_mfc_get_buf_addr_arg_t));

   yuv_size = (pMfcInst->buf_width * pMfcInst->buf_height * 3) >> 1;
   args.get_buf_addr.out_buf_size = yuv_size;
   yuv_buffer = (unsigned int)pMfcInst->yuv_buffer;
   run_index = pMfcInst->run_index;
   out_buf_size = args.get_buf_addr.out_buf_size;
   databuf_vaddr = (unsigned int)s3c_mfc_get_databuf_virt_addr();
   databuf_paddr = (unsigned int)S3C_MFC_BASEADDR_DATA_BUF;
   offset = yuv_buffer + run_index * out_buf_size - databuf_vaddr;  
  
   args.get_buf_addr.out_buf_addr = databuf_paddr + offset;
   args.get_buf_addr.ret_code = S3C_MFC_INST_RET_OK;

   out = copy_to_user((s3c_mfc_get_buf_addr_arg_t *)arg, 
    &args.get_buf_addr, sizeof(s3c_mfc_get_buf_addr_arg_t));

   mutex_unlock(s3c_mfc_mutex);
   break;


========= S3C6400/6410 Demo Application ==========
=                                                =
= 1.   H.264 display                            =
= 2.   MPEG4 display                            =
= 3.   H.263 display                            =
= 4.   VC-1 display                            =
= 5.   4-windows display                        =
= 6.   Display using local path                 =
= 7.   Display using double buffering           =
= 8.   Camera preview & MFC encoding            =
= 9.   MFC decoding & Camera preview            =
= 10. Camera preview & MFC encoding/decoding   =
= 11. Camera input and JPEG encoding           =
= 12. JPEG decoding and display                =
= 13. Exit                                     =
=                                                =
==================================================
Select number --> 1
s3c_mfc_yuv_buffer_mgr_final
address of segment_info=c141c400, address of commit_info =c1426040
s3c_mfc_init_hw: downloading firmware into bitprocessor
s3c_mfc_get_firmware_ver: GET_FW_VER command was issued
s3c_mfc_get_firmware_ver: GET_FW_VER => 0xf202, 0x130e
s3c_mfc_get_firmware_ver: BUSY_FLAG => 0
s3c_mfc_get_stream_buffer_addr: ctx->stream_buffer address 0xc0f46000
s3c_mfc_get_stream_buffer_addr: ctx->phys_addr_stream_buffer address 0x50f46000
s3c_mfc_inst_create: state = 10
s3c_mfc_open: mfc open success
s3c_mfc_ioctl: cmd = 80000f
s3c_mfc_ioctl: cmd = 800005
s3c_mfc_inst_init_dec: strm_leng = 7956
s3c_mfc_inst_init_dec: ctx->inst_no = 0
s3c_mfc_inst_init_dec: ctx->codec_mode = 2
s3c_mfc_inst_init_dec: sequece bit buffer size = 500 (kb)
s3c_mfc_inst_init_dec: RET_DEC_SEQ_SRC_SIZE = 327920
s3c_mfc_inst_init_dec: RET_DEC_SEQ_SRC_FRAME_RATE   = 0
s3c_mfc_inst_init_dec: RET_DEC_SEQ_FRAME_NEED_COUNT = 4
s3c_mfc_inst_init_dec: RET_DEC_SEQ_FRAME_DELAY = 0
s3c_mfc_inst_init_dec: width = 320, height = 240, buf_width = 320, buf_height = 240
s3c_mfc_print_commit_yuv_buffer_info: commit index = 000, base segment index = 0
s3c_mfc_print_commit_yuv_buffer_info: commit index = 000, number of segment = 509
s3c_mfc_get_yuv_buffer_addr: ctx->inst_no : 0
s3c_mfc_get_yuv_buffer_addr: ctx->yuv_buffer : 0xc1040000
s3c_mfc_get_yuv_buffer_addr: ctx->phys_addr_yuv_buffer : 0x51040000
s3c_mfc_ioctl: cmd = 800007
        ########<STREAMINFO> width=320   height=240.
s3c_mfc_ioctl: cmd = 800013
s3c_mfc_ioctl: cmd = 800007
s3c_mfc_ioctl: cmd = 800013
s3c_mfc_ioctl: cmd = 800007
s3c_mfc_ioctl: cmd = 800013
s3c_mfc_ioctl: cmd = 800007
s3c_mfc_ioctl: cmd = 800013
s3c_mfc_ioctl: cmd = 800007
s3c_mfc_ioctl: cmd = 800013



您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP