h264解码器,s3c6410硬件mfc解码分析-H264

    技术2026-05-27  8

    1   源代码如下:

     

     

    int h264_enc_test(){  void *handle;  FILE *fp_in, *fp_out;  int ret, i;  unsigned int width, height;  unsigned int frame_rate, bitrate, gop_num;  unsigned int intraqp, qpmax;  float gamma;  unsigned int num_slices;  unsigned int change_param[2], cur_pic_opt[2];  long size;  unsigned char *p_inbuf;  unsigned char *p_outbuf;  fp_in = fopen("//Storage Card//newsvga.yuv","rb");  if (fp_in == NULL) {  RETAILMSG(1,(L"File not found/n"));  return 0;  }  fp_out = fopen("//Storage Card//news_vga.264", "wb");  if (fp_out == NULL) {  RETAILMSG(1,(L"Cannot open the output file./n"));  return 0;  }  width = 640;  height = 480;  frame_rate = 25;  bitrate = 1000;  gop_num = 1;  intraqp = 10;  qpmax = 10;  gamma = 0.75;  //  /// 1. Create new instance ///  /// (SsbSipH264EncodeInit) ///  //  handle = SsbSipH264EncodeInit(width, height, frame_rate, bitrate, gop_num, intraqp, qpmax, gamma);  RETAILMSG(1,(L"/n HANDLE = 0x%X./n", (DWORD) handle));  if (handle == NULL) {  return 0;  }    /// 2. Set some configuration parameter for initialization ///  /// (SsbSipH264EncodeExe) ///    num_slices = 4;// SsbSipH264EncodeSetConfig(handle, H264_ENC_SETCONF_NUM_SLICES, &num_slices);    /// 3. Initialize the Encoder Instance ///  /// (SsbSipH264EncodeExe) ///    if (SsbSipH264EncodeExe(handle) != SSBSIP_H264_ENC_RET_OK) {  RETAILMSG(1,(L"H.264 Encoder Instance Initialization Failed./n"));  return 0;  }  p_inbuf = SsbSipH264EncodeGetInBuf(handle, 0);  if (p_inbuf == NULL) {  RETAILMSG(1,(L"/n (ERROR)Input buffer is NULL/n"));  return 0;  }  for (i=0; i<650; i++) {  // Reading YUV frame  ret = fread(p_inbuf, 1, (width * height * 3) >> 1, fp_in);  if (ret != ((width * height * 3) >> 1)) {  break;  }/*  if (i == 27) {  change_param[0] = H264_ENC_PARAM_GOP_NUM;  change_param[1] = 20;  SsbSipH264EncodeSetConfig(handle, H264_ENC_SETCONF_PARAM_CHANGE, &change_param);  change_param[0] = H264_ENC_PARAM_F_RATE;  change_param[1] = (2000 << 16) | 40000;  SsbSipH264EncodeSetConfig(handle, H264_ENC_SETCONF_PARAM_CHANGE, &change_param);  }  else if (i >= 49 && i <= 41) {  cur_pic_opt[0] = H264_ENC_PIC_OPT_IDR;  cur_pic_opt[1] = 1;  SsbSipH264EncodeSetConfig(handle, H264_ENC_SETCONF_CUR_PIC_OPT, &cur_pic_opt);  }  else if (i == 57) {  cur_pic_opt[0] = H264_ENC_PIC_OPT_SKIP;  cur_pic_opt[1] = 1;  SsbSipH264EncodeSetConfig(handle, H264_ENC_SETCONF_CUR_PIC_OPT, &cur_pic_opt);  }  else if (i == 46) {  cur_pic_opt[0] = H264_ENC_PIC_OPT_RECOVERY;  cur_pic_opt[1] = 1;  SsbSipH264EncodeSetConfig(handle, H264_ENC_SETCONF_CUR_PIC_OPT, &cur_pic_opt);  }*/  ret = SsbSipH264EncodeExe(handle);  RETAILMSG(1,(L"/n Encode, ret=%d/n", ret));  p_outbuf = SsbSipH264EncodeGetOutBuf(handle, &size);  RETAILMSG(1,(L"/n Output Buf = 0x%X, size = %d/n", (DWORD) p_outbuf, size));  fwrite(p_outbuf, 1, size, fp_out);  }  fclose(fp_in);  fclose(fp_out);  RETAILMSG(1,(L"/n $$ Program ends./n"));  return 0;}

    2 代码分析:

     

    H264的解码流程:@函数Test_Display_H264:1 打开源文件,返回文件描述符in_fd,函数open()2 将文件的相关信息存放的结构体stat中,函数fstat(),比如文件的大小3 将文件映射到内存中,函数mmap()返回首地址,in_addr4 打开post processor,返回文件描述符,pp_fd5 打开frame buffer,返回文件描述符fb_fd;6 函数FrameExtractorInit,初始化帧提取器FrameExtractorInit(FRAMEX_IN_TYPE_MEM, delimiter_h264, sizeof(delimiter_h264), 1);参数:FRAMEX_IN_TYPE_MEM:类型是枚举类型FRAMEX_IN_TYPE,指明输入文件的类型,在此说明是从内存读取文件,还可以是FRAMEX_IN_TYPE_FILEdelimiter_h264:类型是字符数组,有四个成员分别是0x00,0x00,0x00,0x01,与h264编码方式有关;函数功能:构建类型FRAMEX_CTX,并利用参数填充,最后返回其指针pFrameExCtx;7 将文件在内存的起始地址,当前地址以及结束地址保存到类型为FRAMEX_STRM_PTR的量file_strm中;8 函数FrameExtractorFirst,提取第一个帧?FrameExtractorFirst(pFrameExCtx, &file_strm)参数:pFrameExCtx:初始化函数返回的指针file_strm:包含文件地址信息函数功能:根据pFrameExCtx中保存的数据输入类型,选择进入函数:next_delimiter_mem(pCTX, (FRAMEX_STRM_PTR *) in, NULL, 0, NULL);#函数next_delimiter_mem#(FRAMEX_CTX *pCTX, FRAMEX_STRM_PTR *strm_ptr, unsigned char *outbuf, const int outbuf_size, int *n_fill)#参数:#pCTX:就是在帧提取器初始化函数返回的量:保存了文件输入类型以及一个4个字符的字符数组#strm_ptr:保存了文件地址的指针#函数功能:#初始化一个字符数组queue[12],容量为12,依次取出源数据的前4个字符与pCTX中的比较,相等的话就将相应字符填充到queue[12]中,也就是说本次函数执行实现的就是将源数据的前四个个字符内容复制到queue[12]中,同时存储文件地址的量中的当前指针递增。(strm_ptr->p_cur++)9 函数SsbSipH264DecodeInit()创建一个实例返回值:_MFCLIB_H264_DEC类型的指针函数功能:打开mfc设备,并将其映射到内存中,构建类型_MFCLIB_H264_DEC,并执行初始化填充,保存设备打开的描述符,内存地址,还有一个_MFCLIB_H264_DEC_MAGIC_NUMBER=0x92241002,返回指向_MFCLIB_H264_DEC的指针handle10 函数SsbSipH264DecodeGetInBuf,获取输入bufferSsbSipH264DecodeGetInBuf(handle, nFrameLeng)参数:handle,创建实例是返回的类型_MFCLIB_H264_DEC,保存mfc设备的内存映射地址nFrameLeng,初值为0;函数功能:构建类型统一体MFC_ARGS,应该是要传递给mfc的一些参数配置,并将mfc内存的首地址保存到此类型中,调用函数ioctlioctl(pCTX->hOpen, IOCTL_MFC_GET_LINE_BUF_ADDR, &mfc_args)类型MFC_ARGS中的结构体MFC_GET_BUF_ADDR_ARG中会保存返回的数据:输出buffer的地址,输出buffer的大小,返回输出buffer的地址11 函数ExtractConfigStreamH264//H264 CONFIG stream extraction ExtractConfigStreamH264(pFrameExCtx, &file_strm, pStrmBuf, INPUT_BUFFER_SIZE, NULL);参数:pFrameExCtx:初始化函数FrameExtractorInit返回的指向结构体FRAMEX_CTX的指针file_strm:类型FRAMEX_STRM_PTR,保存文件映射到内存的首地址和结束地址pStrmBuf:函数SsbSipH264DecodeGetInBuf返回的输出buffer的地址INPUT_BUFFER_SIZE:宏定义:204800结构体:H264_CONFIG_DATA,成员是长和宽,在此为NULL函数功能://分析源文件获取总共的帧数,并返回nFrameLeng(1)for循环(100)(2)调用函数FrameExtractorPeek(pFrameExCtx, fp, frame_type, sizeof(frame_type), (int *)&nFrameSize);frame_type:容量为10的字符数组,作为输出参数,函数实现就是读取源文件的前十个字符到frame_type中,并相应移动当前指针(3)取返回数组中的元素frame_type[4]的弟八位,如果不是6,7或8退出函数(4)函数FrameExtractorNext#函数next_delimiter_mem12 函数SsbSipH264DecodeExe(handle, nFrameLeng)参数:handle:decode实例化函数SsbSipH264DecodeInit()返回的指向类型_MFCLIB_H264_DEC的指针根据参数对mfc初始化调用函数ioctl(),会在mfc_args中返回信息,将这些信息传递给handle13 函数SsbSipH264DecodeGetConfig(handle, H264_DEC_GETCONF_STREAMINFO, &stream_info);获取stream的配置信息参数:H264_DEC_GETCONF_STREAMINFO:cmd类型stream_info:类型是SSBSIP_H264_STREAM_INFO,将handle在函数SsbSipH264DecodeExe中获取的信息传递给此量和一个全局量g_stream_info13 设置pp_parampp_param的类型是结构体s3c_pp_params_t,是对pp的配置调用ioctl将参数传递给pp14 计算framebuffer的大小fb_size = pp_param.dst_full_width * pp_param.dst_full_height * 2; // RGB565fb_size = pp_param.dst_full_width * pp_param.dst_full_height * 4; // RGB888并将fb映射到内存15 设置OSD相关信息,此时在屏幕上就会画出一块巨型,准备显示了16完成上面的以后就会进入解码环节:#进入while(1),#调用函数SsbSipH264DecodeExe,通知mfc开始解码#函数SsbSipH264DecodeGetConfig(handle, H264_DEC_GETCONF_PHYADDR_FRAM_BUF, pYUVBuf),获取解码后的数据,输出buffer与上面调用的区别是cmdType不同,调用ioctl,会在mfc_args中返回输出buffer的地址和输出buffer的大小//((unsigned int *) value)[0] = mfc_args.get_buf_addr.out_buf_addr; ((unsigned int *) value)[1] = mfc_args.get_buf_addr.out_buf_size;//#函数NextFrameH264,更新frame#将输出buffer的地址传递给pp的配置结构体pp_param,调用ioctl设置pp,后处理并显示#。。。。。下一帧解码17 解码结束deinit decode;munmap;close pp fb.

    本文来自:http://www.crazycoder.cn/Bo-abstracts-selected/Article134077.html

    最新回复(0)