如何利用JM8.6解码器提取码流中P帧宏块(所有4*4块)的运动矢量(考虑B帧,设x264编码的12帧为IDR BBPBBPBBPBP)_涛歌依旧的博客-程序员秘密

技术标签: s6: 视频研究  S1: C/C++  

       说明:

      有好心的读者对下面程序提出了质疑,我觉得有道理,有兴趣的读者可以看看文章后面的评论。感谢那位提出质疑的读者,同时也欢迎各位批评指正。

 

       之前已经讨论过提取P帧各个宏块的第一个4*4块对应的运动矢量,现在考虑提取所有4*4块的运动矢量. 我们知道,在H.264中,宏块是有分块的的,不同情况下分块方式不一样,所以与MPEG2不同,每一个宏块并不只是对应一个运动矢量. 而由于分块的复杂性和多样性,我们可以这样认为:每个4*4块都有一个运动矢量. 比如,对于一个P-skip宏块而言,尽管运动矢量只有一个,但我们认为该宏块的每个4*4块都有一个运动矢量.

 

        在P帧中,为了处理方便,本人认为I宏块有运动矢量,其值为零. 在P帧中,有3种基本的宏块:I宏块,skip形式的P宏块和非skip形式的P宏块. 对于前面两种宏块,仅有唯一的运动矢量,因此提取其每个4*4块的运动矢量时,只需要把一个运动矢量重复16次就OK了,很简单,搞一个16次的循环就可以了,但对于非skip形式的P宏块则相对复杂,因为分块不同, 所以在写的时候要特别注意. 下面仅仅给出提取非skip形式的P宏块的运动矢量的代码: (该代码在readMotionInfoFromNAL函数中)

// first make mv-prediction
SetMotionVectorPredictor (img, pmv, pmv+1, refframe, LIST_0, dec_picture->ref_idx, dec_picture->mv, i, j, 4*step_h, 4*step_v);

for (k=0; k < 2; k++) 
{
  TRACE_STRING("mvd_l0");

  img->subblock_x = i; // position used for context determination
  img->subblock_y = j; // position used for context determination
  currSE.value2 = k<<1; // identifies the component; only used for context determination
  dP->readSyntaxElement(&currSE,img,inp,dP);
  curr_mvd = currSE.value1; 
  
  // vec就是运动矢量
  vec=curr_mvd+pmv[k];           /* find motion vector */
  
  // myFlag用作标记
  // buffer数组用作保存运动矢量的x分量和y分量
  // buffer[0]存x分量,buffer[1]存y分量
  if(myFlag < 2)
	  buffer[myFlag++] = vec;
  if(2 == myFlag)
  {
	  // 一个运动矢量对应的块数为step_h * step_v
	  for(ii=0; ii < step_h * step_v; ii++)
	  {
		if(img->type == P_SLICE) // 保证是P帧(片)
		{
			fprintf(myMV, "%-4d %-4d ", buffer[0], buffer[1]);
		}
	  }
	  myFlag = 0;
  }

 
  for(ii=0;ii<step_h;ii++)
  {
    for(jj=0;jj<step_v;jj++)
    {
      dec_picture->mv  [LIST_0][i4+ii][j4+jj][k] = vec;
      currMB->mvd      [LIST_0][j+jj] [i+ii] [k] = curr_mvd;
    }
  }
}

      

      经与H.264visa提取的结果进行对比,发现上面的代码提取的结果完全正确. OK, 到此为止,P帧运动矢量的提取总算大功告成.

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/stpeace/article/details/8453387

智能推荐

C语言用循环链表解决约瑟夫问题_c语言约瑟夫问题链表_皓阳当空的博客-程序员秘密

循环链表实现代码请参见:#define _CRT_SECURE_NO_WARNINGS#include #include #include #include "CircleLinkList.h"#define M 1000#define N 3typedef struct MYNUM{ CircleLinkNode node; int val;}MyNum;void M

阿里Java学习路线:阶段 1:Java语言基础-Java面向对象编程:第11章: String类常用方法:课时51:字符串与字节_Kenny C的博客-程序员秘密

字符串与字节数组之间也可以实现转换的处理操作,但是需要提醒一下,当进行了字符串与字节转换时,其主要目的是为了进行二进制的数据传输,或者是进行编码转换。No.方法名称类型描述01public String​(byte[] bytes)构造将全部字节数组 变为字符串02public String​(byte[] bytes,int offset,int length)构造将部分字符组变为字符串03public byte[] getBytes​()普通将字符

OC与JS交互之JavaScriptCore_路飞说了的博客-程序员秘密

JavaScriptCore初探在iOS7之前,原生应用和Web应用之间很难通信。如果你想在iOS设备上渲染HTML或者运行JavaScript,你不得不使用UIWebView。iOS7引入了JavaScriptCore,功能更强大,使用更简单。###JavaScriptCore介绍JavaScriptCore是封装了JavaScript和Objective-C桥接的Objective-C ...

几个JAVA常见面试题_火神漫步的博客-程序员秘密

面试考察知识点如下: 一.序列化的实现方式 概念:序列化是将对象状态转换为可保持或传输的格式的过程。与序列化相对的是反序列化,它将流转换为对象。这两个过程结合起来,可以轻松地存储和传输数据。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。 目的:1、以某种存储形式使自定义对象持久化; 2、将对象从一个地方传递到另一个地方。 

#Xlib: connection to ":0.0" refused by server Xlib: No protocol specified_weixin_33774883的博客-程序员秘密

在redhat5系统上运行asmca的时候,提示如下错误:#Xlib: connection to ":0.0" refused by serverXlib: No protocol specified原因是xhost的权限问题。网上搜了一下,都是用root执行 local:username的方式来解决!但是经过本人实验,有时候root执行的时候,也是提示上面的错误:#Xli...

Python-10.1-面向对象_anh_qwh的博客-程序员秘密

Python-10.1-面向对象Python的面向对象一:面向对象概述(ObjectOriented, OO)1、OOP思想2、名词二:类和对象的概念三:类的基本实现1、类的命名2、声明一个类3、实例化类4、访问对象成员5、通过默认内置变量检查类和对象的所有成员四:类和对象的成员分析五:关于self六:面向对象的三大特性1、封装(1)私有 private(2)受保护的封装 protected(3)...

随便推点

电信玩网通游戏延迟应该怎么改善呢?电信玩网通游戏延迟应该怎么改善呢?_weixin_34409357的博客-程序员秘密

电信玩网通游戏延迟应该怎么改善呢?电信玩网通游戏延迟应该怎么改善呢?十年朝夕,万象更新。网络游戏在中国互联网行业已经走过十个年头,从枯涩的文字表述到数字图形化,从单调的背景到恢宏庞大的世界观,从游戏受众数千到数千万,越来越多的游戏玩家因网络卡、掉线问题而烦恼。网络宽带现在区分也比较多:但是几种分布在 电信和网通2大类,现在网络游戏也开始区分电信游戏大区...

面向对象编程类的内聚性_guoyp2126的博客-程序员秘密

高内聚、低耦合是软件设计中非常关键的概念。在面向对象程序设计中类的划分时,类的内聚性越高,其封装性越好,越容易复用,以下由内聚性由高到低做一说明。偶然内聚或巧合内聚(Coincidental):内内的各成分之间没有关联,只是把分散的功能合并在一起;类A内有BCDE四个方法,这四个方法均为public方法,功能含义上各自独立。前端开发api,将不同模块的api放在一起,就是偶然耦合。var api = { //登录 getCaptcha: (param) =&gt; get(apiBase

LIVE 预告 | 华为诺亚韩凯:Transformer in Transformer_智源社区的博客-程序员秘密

近期,华为诺亚方舟实验室的研究者提出了一种新型视觉Transformer网络架构,Transformer in Transformer,性能表现优于谷歌的 ViT 和 Facebook 的...

WINDOWS 10下注册OCX、DLL文件的注意事项_fghler的博客-程序员秘密

1、需要运行regsvr32.exe进行注册,在开始菜单中用管理员权限运行命令行,进入C:\WINDOWS\SYSWOW64文件夹中。2、最好将DLL、OCX文件复制到C:\WINDOWS\SYSWOW64中。...

linux下的SIGINT的作用,linux c sigint等信号不存在,该如何处理_weixin_40005887的博客-程序员秘密

linux c sigint等信号不存在在linux下。/usr/include/signal.h中为什么没有定义SIGINT和SIGOUT这些信号呢?kill-l也显示没有请问这是咋回事啊?------解决方案--------------------/usr/include/signal.h里面有#include/usr/include/bits/signum.h:/*Signalnum...

Signals 和 Slot 的区别_金金2019的博客-程序员秘密

从百度空间看到的文章,我关注的地方是:1、signals前面不可加public、private和protected进行修饰;slots前面可以加,因为Qt说槽函数可以当普通函数使用。2、signals区域的函数必须是void类型,而且这些信号函数没有函数体,也就是说不可以自己定义这些信号函数,你只要声明它就够了,其它不用管,Qt内部自己弄。3、宏定义和函数指针不能用于信号和

推荐文章

热门文章

相关标签