Android硬编转码相关问题

Android MediaCodec转码相关问题


最近在测试各种编码的性能的时候涉及到了android硬编,由于测试的指标有PSNR、SSIM等质量指标,中间遇到了一些坑,稍微记录一下。

硬编的常见用法

大多数实际工程中,硬解或者硬编都是通过Surface中转来做的,经过Surface我们可以做很多事情,比如这个Surface可以是SurfaceView的Surface,或者我们想用Opengl作一些事情,加滤镜或者编辑视频,Surface的方式都提供了方便的解决方式,这也是我们搜索MediaCodec,最常见的使用方式。bigflake(http://bigflake.com/mediacodec)列举出了很多示例代码,其中有一个google CTS代码DecodeEditEncode对于Surface的使用给出了很好的例子。

如果我们想做一个硬解硬编的加速转码(至少相较ffmpeg软解软编还是快一些的),可以参考github项目android-transcoder,这里给出了比较完整的transcode的示例,但是真正想用起来还是需要不少改动的,比如给出的Strategy只支持几个简单的比例,Cancel接口有些问题,这里不具体说了。

我最初测试的有一个很主要的目的是测试PSNR等指标,最初使用了ypresto的demo,但是最终得到的结果总是特别差,比如x264转码psnr能维持在40db的情况,经过Surface android硬解然后硬编基本智能再25db左右(我们最终对比PSNR是将结果mp4解码为YUV,然后直接再YUV三个channel上计算平均PSNR)。但是肉眼看起来其实硬编结果和x264甚至和原视频相差并不大,

硬编转码PSNR很低的问题所在

想到自己平时写shader用gpu加速来进行yuv转rgb的时候用到了yuv转RGB的转换公式,可以参考另外一篇记录color space2中YUV families的介绍,或者直接看一个综合的整理的bt601 & bt709 color matrix,比如bt601 tv range的YUV转RGB的公式为:

bt601 tv range YUV2RGB

bt601 tv range RGB2YUV

看一下这里的YUV2RGB的转换公式,得到的RGB是可能有负值的,比如0, 255, 255得到的RGB就是负值,这里可能有人会说这个公式是针对tv range(也有叫studio range的,就是Y 16-235,UV 16-240),我说一下原因:

  • 1,很多情况下尤其是国内的很多厂商录制出来的视频根本不带着color range信息,即使带着,经过各种渠道的转存流转,基本什么信息也都没有了
  • 2,实际上硬解中是有KEY_COLOR_RANGE参数的,能设置两种值COLOR_RANGE_FULL和COLOR_RANGE_LIMITIED,就是对应着full range和tv range,但是更坑爹的是很多国内厂商根本没有做实现。这里表扬一下良心华为,录制出来的视频都有着完整的color range、color space、color transfer信息,华为录制出来的基本都是tv range视频,在<=480p的时候使用bt601,否则使用HDTV标准bt709,苹果录制出来的m4v文件也是比较良心的。测试了vivo x7录制出来的视频这几个信息都是空着的,难道公司的主要精力都放在了“2000W柔光自拍”上?
  • 3,即使我们使用tv range内的YUV值,比如(16,240,240)也会算出来的Green是负值。其实tv range中的很多YUV值都会算出来RGB值是负的

回归正题,我们显示任何东西,最终都是以RGB的形式显示的,也就是说我们在Surface中的显示也是RGBA的color space,但是实际上上RGBA的值都必须是正值,负值是无法显示的,所以我们自己写shader的时候或者直接交给Surface处理的时候,需要对RGBA的值做clamp处理,裁剪到0-255范围内,也就是负值变成0,超过255的变成255。然后我们对这个clamp以后的RGB值如果再转回YUV值,就跟原始的YUV值相差比较大了。有人会觉得这样不会变色了吗?其实并不会!举个例子:

以yuv(0,0,0)为例(也可以拿16,240,240试试)
1. 先减128 。 (0,-128,-128)
2. 转换为RGB并作clamp  RGB (-179.456,135.424,-226.816)->(0,135,0)
3. 转YUV (79.245,-44.685,-56.565)
4. 色度加128 YUV(79.245,83.315,71.435)
5. 取整,YUV(79,83,71)  转换完毕的值
再转回去:
6. 先减128  YUV (79,-45,-57)
7. 转换为RGB并作clamp  RGB (-0.914,135.178,-0.74)->(0,135,0)
我们发现颜色是一样的,再转一下,看看YUV还会不会变化
8. 转YUV (79.245,-44.685,-56.565)
9. 色度加128 YUV(79.245,83.315,71.435)
10. 得到YUV(79,83,71)  转换完毕的值

上面这个例子我们发现(0,0,0) (79,83,71)实际对应的RGB是一样的,也就是人眼看起来是一样的。但是这样的处理过程对我们比较PSNR造成了很大的问题,计算出来的PSNR很低。x264进行转码却不会有这个问题,还没有自习看ff和x264转码的源码,有待确认具体是怎么个实现,猜测是没有对RGB做clamp,或者根本没有中转RGB。

其他方式做转码

在api 21后,android提供了Image类来做硬解的输出和硬编的输入,Image类基本类似于ffmpeg的AVFrame,里面包含帧图像的各种信息和各个plane,以及stride、width、height、crop x、crop y等信息,也就是说我们可以从Image中得到decode以后的YUV raw data,我们可以这样的到decode 出来的Image:

int result = mDecoder.dequeueOutputBuffer(mBufferInfo, timeout);
Image image = mDecoder.getOutputImage(result);

对于decode以后直接存储为YUV raw data file可以参考VideoToFrames github code(对应的博客是android高效解码得到YUV file)

未完待续


References

  1. Image class & YUV_420_888
  2. YUV_420_888 convert to NV21 & I420
  3. Anroid MediaCodec stuffs
  4. VideoEncoderDecoderTest
  5. Camera and MediaCodec colorspace not match, with images, stack over flow issue
  6. color format of camera and mediacodec, google disscuss
  7. CTS samples EncodeDecodeTest
  8. How to get stride of encoder
  9. ffmpeg command: how to convert to YUV file and how to display it
  10. VideoToYUVFrames github sample code
  11. Android MediaCodec transcoder sample demo, with surface
  12. NV21 NV12 I420 YV12
  13. CTS codecUtils
  14. google CTS
  15. YUV RGB convert
  16. android mediacodec color formats
  17. CTS code: DecodeEditEncodeTest
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容

  • 原文地址 Android MediaCodec stuff 这篇文章是关于 MediaCodec 这一系列类,它主...
    sheepm阅读 67,494评论 17 102
  • MediaCodec的官方文档 一、Android MediaCodec简单介绍 Android中可以使用Medi...
    黄海佳阅读 6,022评论 1 16
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,568评论 25 707
  • 一、文章说明 最近工作实在太忙,很久没有更新文章了,收到很多小伙伴催更的消息,心中实在惭愧,趁着今天有空赶紧更新。...
    风从影阅读 18,508评论 33 117
  • 昨天是陶艺培训第一天,本想昨晚睡觉前总结的,可惜累瘫了,躺在床上动都不想动~昨天的课程内容安排的不算多,三大块——...
    美禾hm阅读 367评论 0 1