android 硬编解码
2018-03-03 17:56:21 test1280 阅读数 213

编解码:Base64编解码

编解码:十六进制编解码中提到,编解码本质上是以不同的数据形式来展示“信息”,可以用二进制来表示,可以用十六进制来表示。

二进制的数据,在计算机中通常是不可读不可打印的。

那有没有一种方式,可以让二进制的数据变成“可读可打印”的?

方法有很多,最常见的是十六进制编解码和Base64编解码。

十六进制编解码之前已介绍过,本文介绍Base64编解码。

百度百科:Base64是一种基于64个可打印字符来表示二进制数据的方法。

Base64编码要求把3个8位字节(3*8=24)转化为4个6位的字节(4*6=24),之后在6位的前面补两个0,形成8位一个字节的形式。 如果剩下的字符不足3个字节,则用0填充,输出字符使用’=’,因此编码后输出的文本末尾可能会出现1或2个’=’(只可能出现0/1/2个等号,否则就是错误的)。

为啥只可能出现0/1/2个等号?动手算算就知道。

将所有的bit位用8n表示(n表示待编码数据字节数量),则当:

n=1时,8*1 mod 6 = 2bit,需要补2个等号
n=2时,8*2 mod 6 = 4bit,需要补1个等号
n=3时,8*3 mod 6 = 0bit,需要补0个等号
n=4时,8*4 mod 6 = 2bit,需要补2个等号
……

Base64编解码前后空间大小变化:

6字节的数据,在编码后占用8字节空间;空间多占用了2B,比原来大:2B/6B=1/3
8字节的数据,在解码后占用6字节空间;空间少占用了2B,比原来小:2B/8B=1/4

Base64编码使得待编码数据增大,增加到原大小的4/3;
Base64解码使得戴洁马数据减小,减小到原大小的3/4;

Demo:

待转换数据(3字节24bit):0x61(a), 0x62(b), 0x63(c):
二进制形式:01100001 01100010 01100011
分组(每6bit一组*4组):011000 010110 001001 100011
每组高位补两个bit的0:00011000 00010110 00001001 00100011
十进制:24 22 9 35

参照对照表(摘自:http://base64.xpcha.com/):

http://base64.xpcha.com/

Base64结果:YWJj

待转换数据(1字节8bit):0x61(a)
二进制形式:01100001
不是6bit整数,需要多补4个bit 0,结果为:01100001 0000
分组:011000 010000
高位补两个bit的0:00011000 00010000
十进制:24 16
转换结果:Y Q
由于Base64规定,Base64结果长度一定是4的倍数,如果不够则以’=’补全,则实际Base64结果为:
YQ==

Code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

static const unsigned char *base64=(unsigned char *)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

/*-----------------------------------------------------------------------------
 * 函数名称:Base64Encode
 * 功能描述:Base64编码
 * 参数说明:base64code:编码结果缓冲区;src:待编码数据;src_len待编码数据长度
 * 返 回 值:编码结果长度(字节)
 * 备    注:注意留有足够的结果缓冲区(src_len/3*4)
 * */
static int Base64Encode(char *base64code, const char *src, int src_len)
{
    int n,buflen,i,j;

    if (src_len == 0)
        src_len = strlen(src);

    buflen=n=src_len;

    for (i=0,j=0; i<=buflen-3; i+=3,j+=4)
    {
        base64code[j] = (src[i]&0xFC)>>2;
        base64code[j+1] = ((src[i]&0x03)<<4) + ((src[i+1]&0xF0)>>4);
        base64code[j+2] = ((src[i+1]&0x0F)<<2) + ((src[i+2]&0xC0)>>6);
        base64code[j+3] = src[i+2]&0x3F;
    }

    if (n%3==1)
    {
        base64code[j] = (src[i]&0xFC)>>2;
        base64code[j+1] = ((src[i]&0x03)<<4);
        base64code[j+2] = 64;
        base64code[j+3] = 64;
        j += 4;
    }
    else if (n%3==2)
    {
        base64code[j] = (src[i]&0xFC)>>2;
        base64code[j+1] = ((src[i]&0x03)<<4) + ((src[i+1]&0xF0)>>4);
        base64code[j+2] = ((src[i+1]&0x0F)<<2);
        base64code[j+3] = 64;
        j += 4;
    }

    for (i=0; i<j; i++)
        base64code[i] = base64[(int)base64code[i]];

    base64code[j] = 0;

    return j;
}

/*-------------------------------------------------------------------------------
 * 函数名称:Base64Decode
 * 功能描述:Base64解码
 * 参数说明:buf:解码结果缓冲区;base64code:待解码数据;src_len:待解码数据长度
 * 返 回 值:解码结果长度(字节)
 * 备    注:注意,buf中解码结果缓冲区中数据不一定可打印
 * */
static int Base64Decode(char *buf, const char *base64code, int src_len)
{
    int n,i,j,pad;

    if (src_len == 0)
        src_len = strlen(base64code);

    if (src_len%4 != 0)
        return -1;

    unsigned char *p=0;
    unsigned char *src=0;

    pad = 0;
    n = src_len;
    src = (unsigned char *)malloc(n);

    for (i=0; i<n; i++)
        src[i]=base64code[i];

    while (n>0&&src[n-1]=='=')
    {
        src[n-1] = 0;
        pad++;
        n--;
    }

    for(i=0; i<n; i++)
    {
        p = (unsigned char *)strchr((const char *)base64, (int)src[i]);
        if (!p)
        {
            free(src);
            return -1;
        }

        src[i] = p-(unsigned char *)base64;
    }

    for (i=0,j=0; i<n; i+=4,j+=3)
    {
        buf[j] = (src[i]<<2) + ((src[i+1]&0x30)>>4);
        buf[j+1] = ((src[i+1]&0x0F)<<4) + ((src[i+2]&0x3C)>>2);
        buf[j+2] = ((src[i+2]&0x03)<<6) + src[i+3];
    }

    j -= pad;
    buf[j] = 0;
    free(src);

    return j;
}

int main()
{
    // 测试Base64编码
    {
        char buff[1024] = "";
        char *str = "0123456789abcdef";

        memset(buff, 0, 1024); // clear
        int base64len = Base64Encode(buff, str, strlen(str));
        buff[base64len] = 0;

        printf("%s\n", buff);
    }

    // 测试Base64解码
    {
        char buff[1024] = "";
        char *str = "MDEyMzQ1Njc4OWFiY2RlZg==";

        memset(buff, 0, 1024);
        int base64len = Base64Decode(buff, str, strlen(str));

        printf("%s\n", buff);
    }

    return 0;
}

编译 && 执行:

[jiang@localhost jiang]$ gcc -o Base64 Base64.c 
[jiang@localhost jiang]$ ./Base64 
MDEyMzQ1Njc4OWFiY2RlZg==
0123456789abcdef

需要注意:

为啥在编码时需要指明待编码数据长度?

原因是待编码数据不一定可读,是二进制数据,即,可能存在0x00,很显然不可以用strlen,那我在编码函数中如何知道其待编码数据长度呢?不知道!所以,调用编码函数时需要显示地指明待编码数据长度。

引用:

1.http://base64.xpcha.com/

2017-03-03 16:52:42 NB_vol_1 阅读数 2581

硬件编解码介绍



音视频编解码的两种方式


    对视频数据编解码一般有两种方式:

    1、软件的方式。使用常规的x264、x265等软件编解码器对数据进行处理,优点是灵活,可以根据需要进行定制,缺点是速度比较慢
    2、硬件的方式。使用硬件芯片厂商提供的API进行编解码,这些编解码器已经被集成到了硬件底层,优点是速度快,缺点是与平台相关,而且不够灵活。



常见的硬件编码


    常见的硬件编解码方式有:
    1、Android平台提供的MediaCodec 
    2、iOS平台提供的Video ToolBox
    3、Intel提供的QuickSync 

android 硬编解码 相关内容

2018-03-03 16:13:29 test1280 阅读数 1094

编解码:十六进制编解码

信息有多种表现形式:二进制、十进制、十六进制、字符串…

在计算机中,信息是以二进制的形式来表现。

可以人为定义:0就是假,1就是真,等等。

所谓编解码,是将一种数据以另一种形式来表现,若正向变换称为编码,则其逆向过程则为解码。

计算机中,数据的本质是一串二进制0和1的字符串。

例如,二进制字符串0a代表十进制字符串10,十进制字符串255以二进制的形式表现则为0xff。

我们定义:

由二进制编码为十六进制的过程,称为十六进制码;
由十六进制编码为二进制的过程,称为十六进制码;

规则如下:

二进制数据:0x0a,在计算机中通常占1字节存储空间,即8bit,我们将前4bit取出,以十六进制表示,为字符串第一个字符:’0’;我们将后4bit取出,以十六进制表示,为字符串第二个字符:’a’,即,0000–>‘0’,1010–>’a’,最终结果为字符串”0a”。

若存在多个字节数据,则从左到右,依次编码。

例如:

0xab 0xcd 0xef 编码为十六进制:”abcdef”。

可见,编解码的本质是将数据以另一种不同形式表示的过程,数据信息本身并不发生改变。

如何将上面的解释“以程序代码的形式”进行“编码”?(^_^)


以上的文字包含了我此篇文章的信息,是以中英文形式表示,下面的代码,是将此篇文章的信息,以C程序的形式表示,这也是一种编解码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

/*--------------------------------------------------------------
 * 函数名称:bin2hex
 * 功能描述:对Binary数据以十六进制形式进行编码
 * 参数说明:bin:待编码数据;blen:待编码数据长度
 * 返 回 值:
 * 备    注:一字节数据0xab编码为字符串"ab"
 * */
void bin2hex(const unsigned char *bin, size_t blen)
{
    static char bin2char[] = "0123456789abcdef";
    char *hex = malloc(blen*2+1); // The Last '1' For C 'NULL'
    memset(hex, 0, blen*2+1);
    for (size_t i = 0; i < blen; i++)
    {
        hex[i*2] = bin2char[bin[i]>>4];
        hex[i*2+1] = bin2char[bin[i]&0x0f];
    }
    printf("%s\n", hex);
    free(hex);
}

/*--------------------------------------------------------------
 * 函数名称:hex2num
 * 功能描述:十六进制字符转换为十进制数字
 * 参数说明:ch:待转换十六进制字符
 * 返 回 值:转换后的十进制数字
 * 备    注:忽略错误
 * */
unsigned int hex2num(char ch)
{
    if (ch >= '0' && ch <= '9')
        return ch - '0';
    else if (ch >= 'a' && ch <= 'z')
        return ch - 'a';
    else if (ch >= 'A' && ch <= 'Z')
        return ch - 'A';
    else
        return 0; // error
}

/*--------------------------------------------------------------
 * 函数名称:hex2bin
 * 功能描述:十六进制形式解码为Binary数据
 * 参数说明:hex:待解码十六进制数据
 * 返 回 值:Binary数据
 * 备    注:可由Hex数据推导出Bin数据长度(Hex-Len = 2 * Bin-Len)
 * */
unsigned char *hex2bin(const char *hex)
{
    size_t blen = strlen(hex) / 2;
    unsigned char *bin = malloc(blen);
    for (size_t i = 0; i < blen; i++)
        bin[i] = hex2num(hex[i*2])*16 + hex2num(hex[i*2+1]);
    return bin;
}

int main()
{
    const char *hex = "0123456789abcdef";
    unsigned char *bin = hex2bin(hex);
    bin2hex(bin, 8);
    free(bin);
    return 0;
}

编译 && 执行:

[jiang@localhost jiang]$ gcc -o HexWithBin HexWithBin.c -std=c99
[jiang@localhost jiang]$ ./HexWithBin 
0123456789012345

请注意:

编解码的结果仅仅是数据表现形式不同,但结果所蕴含的信息数据是完全相同的。
编解码不等于加解密,更不等于摘要,他们三者是完全独立的概念,之间相互无任何关联性。

android 硬编解码 相关内容

2019-03-14 15:37:31 hr963171814 阅读数 15

如何评判一个编解码框架的优劣:

1.是否支持跨语言
2.编码后的码流大小
3.编解码的性能
4.类库是否小巧,api使用方便度
5.使用者开发工作量和难度

java序列化的目的

1.网络传输
2.对象持久化

java序列化的缺点

1.无法跨语言,序列化和反序列化只能java实现
2.序列化后的码流过大
3.序列化性能太低

业界主流的编解码框架

1.Google的protobuf

2.Facebook的Thrift

3.Jboss的Marshalling

android 硬编解码 相关内容

2018-12-28 11:42:06 qq_25484147 阅读数 119

为何使用编解码框架

我的理解是在网络应用程序中,只能是通过字节传输,这么就会造成一个问题,在目标应用程序之间需要对字节转化为各个程序需要的数据类型,这个事情就是由编解码器做的处理。编码器做的是将数据类型转化为字节,而解码器就是将字节转化为各种数据类型。

解码器

在Netty中解码器有两种方式,一种是将字节转化为各种数据类型:ByteToMessageDecoder 和ReplayingDecoder。一种是一种数据类型转化为另外一种数据类型:MessageToMessageDecoder。

ByteToMessageDecoder

package com.bobo.netty.codec;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

import java.util.List;

/**
 * ByteToMessage的扩展类
 * @author wuxiaobo@didachuxing.com
 * @create 2018-12-27 22:51
 **/
public class ByteToMessageImpl  extends ByteToMessageDecoder{

    /**
     * 这个方法被调用的时候将会传入一个包含了传入数据的ByteBuf,
     * 以及一个用来添加解码消息的List,对这个方法的调用将会反复进行,
     * 直到确定没有新的元素添加到该List,或者该ByteBuf中没有更多
     * 可读取的字节位置,如果这个List不为空,那么它的内容将会传递到
     * ChannelPipeline中的下一个ChannelInboundHandler
     * @param ctx
     * @param in
     * @param out
     * @throws Exception
     */
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        // 检查是否至少有4个字节可读
        if (in.readableBytes() >= 4) {
            //将传入的字节转化为int类型,放在List中,
            //然后传递到ChannelPipeLine中的下一个ChannelInboundHandler
            out.add(in.readInt());
        }
    }


    /**
     * 当Channel的状态变成为非活动的时候,这个方法就会被调用一次
     * @param ctx
     * @param in
     * @param out
     * @throws Exception
     */
    @Override
    protected void decodeLast(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {

    }
}

ReplayingDecoder

package com.bobo.netty.codec;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ReplayingDecoder;

import java.util.List;

/**
 * ReplayingDecoder实现类
 * @author wuxiaobo@didachuxing.com
 * @create 2018-12-28 9:47
 **/
public class ReplayingDecoderImpl extends ReplayingDecoder<Void> {

    /**
     * 通过这个类,可以不用去调用readableBytes,
     * 
     * @param ctx
     * @param in
     * @param out
     * @throws Exception
     */
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        out.add(in.readInt());
    }
}

当没有足够的字节可以使用的使用,这个in.readInt方法就会抛出一个Error,其将在基类中被捕获并且处理,当由恩过可读数据的时候,这个decode方法将再一次被调用。

注意:1.并不是所有的ByteBuf 操作都被支持,如果调用了一个不被支持的方法,将会抛出一
个UnsupportedOperationException。2.ReplayingDecoder 稍慢于ByteToMessageDecoder。

抽象类MessageToMessageDecoder

这里说的是如何将一个实体转化为另一个实体。

package com.bobo.netty.codec;

import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageDecoder;

import java.util.List;

/**
 * 将一个实体转化为另一个实体
 * @author wuxiaobo@didachuxing.com
 * @create 2018-12-28 10:13
 **/
public class MessageToMessageDecoderImpl extends MessageToMessageDecoder<Integer> {

    /**
     * 这里是将一个Integer转化为String类型
     * @param ctx
     * @param msg
     * @param out
     * @throws Exception
     */
    @Override
    protected void decode(ChannelHandlerContext ctx, Integer msg, List<Object> out) throws Exception {
        
        out.add(String.valueOf(msg));
    }
}

TooLongFrameException 类

由于Netty 是一个异步框架,所以需要在字节可以解码之前在内存中缓冲它们。因此,不能让解码器缓冲大量的数据以至于耗尽可用的内存。为了解除这个常见的顾虑,Netty 提供了TooLongFrameException 类,其将由解码器在帧超出指定的大小限制时抛出。

编码器

MessageToByteEncoder

package com.bobo.netty.codec;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;

/**
 * 编码器实现
 *
 * @author wuxiaobo@didachuxing.com
 * @create 2018-12-28 10:25
 **/
public class MessageToByteEncoderImpl extends MessageToByteEncoder<Short>{

    /**
     * 将数据实体转化为字节
     * @param ctx
     * @param msg
     * @param out
     * @throws Exception
     */
    @Override
    protected void encode(ChannelHandlerContext ctx, Short msg, ByteBuf out) throws Exception {
        out.writeShort(msg);
    }
}

MessageToMessageEncoder

package com.bobo.netty.codec;

import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageEncoder;

import java.util.List;

/**
 * MessageToMessageEncoder的实现类
 * @author wuxiaobo@didachuxing.com
 * @create 2018-12-28 10:27
 **/
public class MessageToMessageEncoderImpl extends MessageToMessageEncoder<Integer> {

    /**
     * 这里展示了将一个Integer类型的String写入到List中
     * @param ctx
     * @param msg
     * @param out
     * @throws Exception
     */
    @Override
    protected void encode(ChannelHandlerContext ctx, Integer msg, List<Object> out) throws Exception {
       out.add(String.valueOf(msg));
    }
}

Netty中预置的编解码器

通过SSL/TLS保护Netty应用程序

基于HTTP/HTTPS的 应用程序

HTTP解码器

HTTP请求的组成成分
在这里插入图片描述

HTTP响应的组成部分
在这里插入图片描述
在这里插入图片描述

HTTP编码器和解码器

这一块儿暂时不是很懂,所以先留着这里,如果需要的时候再学习

名称 描述
HttpRequestEncoder 将HttpRequest、HttpContent 和LastHttpContent 消息编码为字节
HttpResponseEncoder 将HttpResponse、HttpContent 和LastHttpContent 消息编码为字节
HttpRequestDecoder 将字节解码为HttpRequest、HttpContent 和LastHttpContent 消息
HttpResponseDecoder 将字节解码为HttpResponse、HttpContent 和LastHttpContent 消息
HttpObjectAggregator 聚合HTTP消息
HttpContentDecompressor 处理来自服务器的压缩内容
HttpContentCompressor 在服务器端压缩数据
SslHandler 使用HTTPS

空闲的连接和超时

检测空闲连接以及超时对于及时释放资源来说是至关重要的。由于这是一项常见的任务,
Netty 特地为它提供了几个ChannelHandler 实现。

名称 描述
IdleStateHandler 当连接空闲时间太长时,将会触发一个IdleStateEvent 事件。然后,你可以通过在你的ChannelInboundHandler 中重写userEvent-Triggered()方法来处理该IdleStateEvent 事件
ReadTimeoutHandler 如果在指定的时间间隔内没有收到任何的入站数据,则抛出一个Read-TimeoutException 并关闭对应的Channel。可以通过重写你的ChannelHandler 中的exceptionCaught()方法来检测该Read-TimeoutException
WriteTimeoutHandler 如果在指定的时间间隔内没有任何出站数据写入,则抛出一个Write-TimeoutException 并关闭对应的Channel 。可以通过重写你的ChannelHandler 的exceptionCaught()方法检测该WriteTimeout-Exception

android 硬编解码 相关内容

没有更多推荐了,返回首页