这段时间在做Android平台下的网络摄像机的兼容,摄像机的通讯采用Http1.1协议。现将遇到的问题简单总结一下:
1. Http协议中需要用到身份认证部分,不同厂家的摄像机所采取的方案可能有所不同,但是大体无外乎都是将摄像机的用户名和密码简单的用Base64加密转换后封装成特定字段反馈给摄像机,摄像机对接收到的加密字段进行匹配。常见的方法是:Base64(用户名:密码)(将用户名和密码用‘:’连接,然后对其进行Base64转换)。
2. 视频数据传输一般是采用Rtsp实时数据流传输协议,对Rtsp数据流进行拆包组帧转换为H264数据帧成了首要解决的问题。这个过程可以放在Android上层用Java实现,也可以放到JNI底层实现。本人最初在上层用Java实现了Rtsp的拆包组帧,最后在实际的运行当中发现:低分辨率的摄像机可以勉强运行,一旦连接高分辨率的摄像机就会出现丢帧和花屏的现象。最后不得不将该模块用C重写封装成接口放到底层,运行1280*720分辨率都很流畅。总结:Java实现数据转换的效率不高,最好放到JNI底层来实现复杂的数据运算。
3. H264解码器的问题。最初是从网上下载了一个经过裁剪的H264解码器(基于FFMPEG开源项目)。在测试中发现有时候会出现底层解码错误导致整个程序崩溃,这个问题困扰了我们很久。最后决定移植一个完整的ffmpeg解码器来解决这个问题,网上有众多网友做过相关的事情。经过漫长的接口封装调试最终成功解决。从1280*720、640*360、到320*240分辨率的测试
都很流畅(Android.mk、JNI接口文件,解码器源码等相关代码将上传到资源)
项目中后来用到的解码器为ffmpeg1.2版本,通过移植其H264视频解码模块来满足了应用项目的要求,下面贴上Jni接口的C源码:
#include <string.h>
#include <jni.h>
#include <stdio.h>
#include <stdlib.h>
#include <android/log.h>
#include<netinet/in.h>
#include "ffmpeg/libavformat/avformat.h"
#include "ffmpeg/libavcodec/avcodec.h"
#include "ffmpeg/libswscale/swscale.h"
AVCodec *m_pCodec = NULL;
AVCodecContext *m_pCodecCtx = NULL;
AVFrame *m_pFrame = NULL;
struct SwsContext *pSwsCtx = NULL;
AVPacket m_packet;
int m_width = 0;
int m_height = 0;
const int MAX_VIDEO_W = 1280;
const int MAX_VIDEO_H = 720;
static int g_bInit = 0;
int g_iFrame = 0;
//picture
char *fill_buffer;
AVFrame *frame_rgb;
struct SwsContext *img_convert_ctx;
jboolean bPicture = JNI_FALSE;
///
#define MAX_RGB_BUF 1280*720*3
// 视频参数定义
#define PT_H264 96
#define PT_G726 97
#define PT_G711 8
#define PT_DATA 100
// global
static int g_iConnState = 0;
int ret = -1;
int outSize = 0;
const int nVideoLen = 1280 * 720;
const int nBufLen = 512000;
char *g_pVideoData = NULL;
char *g_pBufData = NULL;
int g_nCopyLen = 0;
int g_nBufLen = 0;
int g_nFullPackLen = 0;
int g_nNeedLen = 0;
unsigned int g_ts = 0;
int g_tsLen = 0;
char *m_srcInbuf = NULL;
//2. RTP数据包头格式:
typedef struct {
/* byte 0 */
unsigned short cc :4; /* CSRC count */
unsigned short x :1; /* header extension flag */
unsigned short p :1; /* padding flag */
unsigned short version :2; /* protocol version */
/* byte 1 */
unsigned short pt :7; /* payload type */ //pt说明: 96=>