3D-Wave算法是2D-Wave的扩展。3D-Wave相对于只在帧内并行的2D-Wave来说,多了帧间并行,不用等待前一帧完成解码后才开始下一帧的解码,而是只要宏块的帧间参考部分以及帧内依赖宏块解码完毕即可开始当前宏块的解码。由于帧间参考所用的运动向量是动态的值,因此称此算法为Dynamic 3D-Wave。

在3D-Wave算法中,宏块的帧间参考部分是指宏块进行运动补偿时需要依赖的相应参考帧的某些宏块,所依赖的这些帧间宏块当中,最右下角的那个宏块会是最晚被解码的,因此我们可以把它当作帧间依赖。另外,如果当前宏块采用的是双向预测,那么它将有两个帧间依赖。

3D-Wave实现

如前文所说,3D-Wave算法中,宏块需要分别等待帧内依赖、帧间依赖解码完成才能开始当前宏块的解码操作。由于这两个依赖的完成时间会有先后之分,因此可能会出现以下两种情况

  情形 1 情形 2
step 1 帧间依赖解码完成 帧内依赖解码完成,启动解码
step 2 帧内依赖解码完成,启动解码 帧间依赖解码完成
step 3 解码宏块 解码宏块
step 4 通知依赖于本宏块的其它宏块 通知依赖于本宏块的其它宏块

其中解码宏块必须由帧内依赖解码完成后一同启动,因为帧间依赖在解码完成时,并不知道哪个宏块会依赖于它,而帧内依赖由于位置是固定的,因此在帧内依赖解码完成后能直接启动解码,得到mvp(运动向量的预测值)然后求得mv,从而确定当前宏块与帧间依赖的关系,帧间依赖根据这个关系来通知当前宏块:帧间依赖解码已完成。

根据上面的分析,有如下实现方案:

用一个三位数组Ready[f][x][y]来表示某一帧的某一宏块是否解码完成;

用一个三位数组KoL[f][x][y]来表示某一帧的某一宏块的帧间依赖关系,(f,x,y)是当前宏块,KoL[f][x][y]内存放的是帧间依赖于这个宏块的其它宏块,用链表实现;

在帧间依赖先解码完成的情况下,去把Ready数组中该帧间依赖所在的位置的元素置1。待帧内依赖解码完成,当前宏块开始解码时,去查看Ready数组中帧间依赖的元素,会得知该帧间依赖已解码完成。

在帧内依赖先解码完成的情况下,当前宏块开始解码,去查看Ready数组中帧间依赖的元素时,会发现帧间依赖尚未解码完成,因此需要用KoL把当前宏块与帧间依赖关联在一起,然后解码任务会由于帧间依赖没有解码完成而被挂起。待帧间依赖解码完成,去把Ready数组中的相应元素置1,并通过KoL链表数组通知帧间依赖于该宏块的宏块,恢复解码任务。

伪代码如下

void decode_mb(int x, int y, int f, bool mv_pred_done, int RMB_start)
{
/*
*一个宏块由于“挂起”与“恢复”,可能会重复执行decode_mb,
*而求mvp等步骤只需要执行一次
*/
if(!mv_pred_done)
{
/* 求mvp */
Motion_Vector_Prediction(x, y);
/* 通过mvp得到mv,得到帧间依赖,帧间依赖可能不止一个 */
RMB_List = RMB_Calculation(x, y);
} /* 遍历帧间依赖,如果有依赖没解码完成,应该“挂起”,即return */
for(i = RMB_List.start; i<RMB_List.last; i++)
{
(g,u,v) = get_frame_number_and_MB_coord(RMB_List.rmb[i]);
if(!Ready[g][u][v])
{
/* 有依赖没解码完成,把当前MB加入到它的KoL */
Subscribe(Kol[g][u][v], x, y, f, i+1);
/* “挂起” */
return;
}
} /* 实际的宏块重建工作 */
Picture_Prediction(x, y);
Deblocking_Info(x, y);
Deblocking_Filter(x, y); Ready[f][x][y] = true; /* 恢复帧间依赖于本MB的MB */
for(each quadruple(u, v, g, start) in KoL[f][x][y])
tp_submit(decode_mb, u, v, g, ture, start); /*
*from 2D-Wave
*decrement dependency counters and tail submit
*/
if(y < WIDTH-1){
atomic_dec(dep_count[x][y+1]);
if(dep_count[x][y+1] == 0)
tp_submit(decode_mb, x, y+1, f, false, 0);
}
if(x < HEIGHT-1 && y != 0){
atomic_dec(dep_count[x+1][y-1]);
if(dep_count[x+1][y-1] == 0)
tp_submit(decode_mb, x+1, y-1, f, false, 0);
}
}

优化

优化思路与2D-Wave算法一样,尽可能使得一个核心解码相邻宏块。

void decode_mb(int x, int y, int f, bool mv_pred_done, int RMB_start)
{
down_left_avail = 0;
right_avail = 0; do{
/*
*一个宏块由于“挂起”与“恢复”,可能会重复执行decode_mb,
*而求mvp等步骤只需要执行一次
*/
if(!mv_pred_done)
{
/* 求mvp */
Motion_Vector_Prediction(x, y);
/* 通过mvp得到mv,得到帧间依赖,帧间依赖可能不止一个 */
RMB_List = RMB_Calculation(x, y);
} /* 遍历帧间依赖,如果有依赖没解码完成,应该“挂起”,即return */
for(i = RMB_List.start; i<RMB_List.last; i++)
{
(g,u,v) = get_frame_number_and_MB_coord(RMB_List.rmb[i]);
if(!Ready[g][u][v])
{
/* 有依赖没解码完成,把当前MB加入到它的KoL */
Subscribe(Kol[g][u][v], x, y, f, i+1);
/* “挂起” */
return;
}
} /* 实际的宏块重建工作 */
Picture_Prediction(x, y);
Deblocking_Info(x, y);
Deblocking_Filter(x, y); Ready[f][x][y] = true; /* 恢复帧间依赖于本MB的MB */
for(each quadruple(u, v, g, start) in KoL[f][x][y])
tp_submit(decode_mb, u, v, g, ture, start); /*
*from 2D-Wave
*decrement dependency counters and tail submit
*/
if(y < WIDTH-1){
atomic_dec(dep_count[x][y+1]);
if(dep_count[x][y+1] == 0)
right_avail = 1;
}
if(x < HEIGHT-1 && y != 0){
atomic_dec(dep_count[x+1][y-1]);
if(dep_count[x+1][y-1] == 0)
right_avail = 1;
} /* give priority to right MB */
if(down_left_avail && right_avail)
{
tp_submit(decode_mb, x+1, y-1, f, false, 0);
y++;
mv_pred_done = false;
}
else if(down_left_avail)
{
x++; y--;
mv_pred_done = false;
}
else if(right_avail)
{
y++;
mv_pred_down = false;
}
}while(down_left_avail || right_avail);
}

没资源时挂起任务,有资源时恢复任务,这是一种常见的任务同步需求。我们这里由于假设任务是非抢占类型的,即一个任务不能中间停止,只能从开头执行结束,因此用return代替挂起,重启任务代替恢复。如果在一般的操作系统上实现的话,有各种各样的同步工具,如semaphore、lock、Event等。

关于h.264并行解码算法的更详细分析请参考Ben Juurlink · Mauricio Alvarez-Mesa · Chi Ching Chi · Arnaldo Azevedo · Cor Meenderinck · Alex Ramirez:《Scalable Parallel Programming Applied to H.264/AVC Decoding》

h.264并行解码算法3D-Wave实现(基于多核共享内存系统)的更多相关文章

  1. h.264并行解码算法2D-Wave实现(基于多核共享内存系统)

    cache-coherent shared-memory system 我们最平常使用的很多x86.arm芯片都属于多核共享内存系统,这种系统表现为多个核心能直接对同一内存进行读写访问.尽管内存的存取 ...

  2. h.264并行解码算法2D-Wave实现(基于多核非共享内存系统)

    在<Scalable Parallel Programming Applied to H.264/AVC Decoding>书中,作者基于双芯片18核的Cell BE系统实现了2D-Wav ...

  3. h.264并行解码算法分析

    并行算法类型可以分为两类 Function-level Decomposition,按照功能模块进行并行 Data-level Decomposition,按照数据划分进行并行 Function-le ...

  4. h.264并行熵解码

    在前面讨论并行解码的章节中,我们专注于讨论解码的宏块重建部分,甚至把宏块重建描述成宏块解码,这是因为在解码工作中,宏块重建确实占了相当大的比重,不过解码还包含其它的部分,按照解码流程可粗略分为: 读取 ...

  5. 让dcef3支持mp3和h.264 mp4解码播放

    嵌入式Chromium框架(简称CEF) 是一个由Marshall Greenblatt在2008建立的开源项目,它主要目的是开发一个基于Google Chromium的Webbrowser控件.CE ...

  6. h.264硬件解码

    // H264HWDecoder.m // H264EncoderDecoder // // Created by lujunjie on 2016/11/28. // Copyright © 201 ...

  7. 音视频编解码技术(一):MPEG-4/H.264 AVC 编解码标准

    一.H264 概述 H.264,通常也被称之为H.264/AVC(或者H.264/MPEG-4 AVC或MPEG-4/H.264 AVC) 1. H.264视频编解码的意义 H.264的出现就是为了创 ...

  8. 【视频编解码·学习笔记】2. H.264简介

    一.H.264视频编码标准 H.264视频编码标准是ITU-T与MPEG合作产生的又一巨大成果,自颁布之日起就在业界产生了巨大影响.严格地讲,H.264标准是属于MPEG-4家族的一部分,即MPEG- ...

  9. H.264视频的RTP荷载格式

    Status of This Memo This document specifies an Internet standards track protocol for the   Internet ...

随机推荐

  1. android开发之Bundle使用

    android开发中,我们经常需要在两个activity之间传递数据,最常用的莫过于使用intent.putXXX(),可是很多时候我们也会这样: Bundle bundle = new Bundle ...

  2. Spring整合CXF步骤,Spring实现webService,spring整合WebService

    Spring整合CXF步骤 Spring实现webService, spring整合WebService >>>>>>>>>>>> ...

  3. 学习java随笔第六篇:数组

    一维数组 创建一维数组并输出 public class OneDimensionalArray { public static void main(String argas[]) { int i[]= ...

  4. c语言学习之基础知识点介绍(七):循环结构

    本节主要介绍循环结构 一.while循环 /* 语法: while(表达式){ //循环体; } 注意:循环变量.循环条件和循环控制语句三者缺一不可. 例如: */ ; //循环变量 ){ //循环条 ...

  5. 带参数的查询防止SQL注入攻击

    把单引号替换成两个单引号,虽然能起到一定的防止SQL注入攻击的作用,但是更为有效的办法是把要拼接的内容做成“参数” SQLCommand支持带参数的查询,也就是说,可以在查询语句中指定参数: 参数的设 ...

  6. 浏览器兼容问题----Firefox不兼容event的解决方法

    一.event.srcElement:当前事件的源: 在IE下,event对象有srcElement属性,但是没有target属性;Firefox下,event对象有target属性,但是没有srcE ...

  7. iOS开发进阶--1.多线程简介

    学习是由已知的知识模型推理未知的知识模型的的过程. 本文适合学习完objective-c基础,想进一步提高做iOS开发的同学阅读. 在说线程的时候,我们先看看进程. 1.进程 每一个运行在系统中的应用 ...

  8. iOS中常用技术链接

    1.弹幕技术 http://www.jianshu.com/p/f39b8abc8008 2.通过CAGradientLayer制作渐变色效果 http://blog.it985.com/7986.h ...

  9. Ubuntu系列Crontab日记记录

    修改rsyslog文件,将/etc/rsyslog.d/50-default.conf 文件中的#cron.*前的#删掉 重启rsyslog服务service rsyslog restart 重启cr ...

  10. redis【摘自网上,只为以后查看】

    ubuntu安装启动redis 1.下载安装 cd /tmp wget http://redis.googlecode.com/files/redis-2.2.13.tar.gz tar -zxf r ...