手中的板子的CPU是三星coretex-a9的,板子有硬编能力(至于是哪个芯片没仔细看),通过一至两周的努力,成功实现硬编码成H.264并投递到rtmp服务器。大体实现如下:
1.使用ffmpeg取摄像头YUV数据;
2.将YUV数据喂给三星硬编API;
3.将硬编的数据通过librtmp投递;
废话少说,上代码,代码有些糙,将就看:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavdevice/avdevice.h>
#include <libswscale/swscale.h>
#include <librtmp/rtmp.h>
#include <nx_fourcc.h>
#include <nx_vip.h> // VIP
#include <nx_dsp.h> // Display
#include "nx_video_api.h" // Video En/Decoder
#include "sps_decode.h"
#define MAX_FILE_NAME 1024
#define MAX_SEQ_BUF_SIZE (4*1024)
//定义包头长度,RTMP_MAX_HEADER_SIZE=18
#define RTMP_HEAD_SIZE (sizeof(RTMPPacket)+RTMP_MAX_HEADER_SIZE)
//存储Nal单元数据的buffer大小
#define BUFFER_SIZE 327680
#define MAX_PACKET_BYTES (RTMP_HEAD_SIZE+BUFFER_SIZE)
//搜寻Nal单元时的一些标志
#define GOT_A_NAL_CROSS_BUFFER BUFFER_SIZE+1
#define GOT_A_NAL_INCLUDE_A_BUFFER BUFFER_SIZE+2
#define NO_MORE_BUFFER_TO_READ BUFFER_SIZE+3
enum
{
VIDEO_CODECID_H264 = 7,
};
/**
* _NaluUnit
* 内部结构体。该结构体主要用于存储和传递Nal单元的类型、大小和数据
*/
typedef struct _NaluUnit
{
int type;
int size;
unsigned char *data;
}NaluUnit;
typedef struct _RTMPMetadata
{
// video, must be h264 type
unsigned int nWidth;
unsigned int nHeight;
unsigned int nFrameRate; // fps
unsigned int nVideoDataRate; // bps
unsigned int nSpsLen;
unsigned char* Sps;
unsigned int nPpsLen;
unsigned char* Pps;
// audio, must be aac type
bool bHasAudio;
unsigned int nAudioDatarate;
unsigned int nAudioSampleRate;
unsigned int nAudioSampleSize;
int nAudioFmt;
unsigned int nAudioChannels;
char pAudioSpecCfg;
unsigned int nAudioSpecCfgLen;
} RTMPMetadata,*LPRTMPMetadata;
static void dumpdata( void *data, int len, const char *msg )
{
int i=0;
unsigned char *byte = (unsigned char *)data;
printf("Dump Data : %s", msg);
for( i=0 ; i<len ; i ++ )
{
if( i!=0 && i%16 == 0 ) printf("\n\t");
printf("%.2x", byte[i] );
if( i%4 == 3 ) printf(" ");
}
printf("\n");
}
//网络字节序转换
char * put_byte( char *output, uint8_t nVal )
{
output[0] = nVal;
return output+1;
}
char * put_be16(char *output, uint16_t nVal )
{
output[1] = nVal & 0xff;
output[0] = nVal >> 8;
return output+2;
}
char * put_be24(char *output,uint32_t nVal )
{
output[2] = nVal & 0xff;
output[1] = nVal >> 8;
output[0] = nVal >> 16;
return output+3;
}
char * put_be32(char *output, uint32_t nVal )
{
output[3] = nVal & 0xff;
output[2] = nVal >> 8;
output[1] = nVal >> 16;
output[0] = nVal >> 24;
return output+4;
}
char * put_be64( char *output, uint64_t nVal )
{
output=put_be32( output, nVal >> 32 );
output=put_be32( output, nVal );
return output;
}
char * put_amf_string( char *c, const char *str )
{
uint16_t len = strlen( str );
c=put_be16( c, len );
memcpy(c,str,len);
return c+len;
}
char * put_amf_double( char *c, double d )
{
*c++ = AMF_NUMBER; /* type: Number */
{
unsigned char *ci, *co;
ci = (unsigned char *)&d;
co = (unsigned char *)c;
co[0] = ci[7];
co[1] = ci[6];
co[2] = ci[5];
co[3] = ci[4];
co[4] = ci[3];
co[5] = ci[2];
co[6] = ci[1];
co[7] = ci[0];
}
return c+8;
}
unsigned int g_nStop;
unsigned int m_nFileBufSize;
unsigned int nalhead_pos;
RTMP* m_pRtmp;
RTMPMetadata g_metaData;
char m_pBuff[MAX_PACKET_BYTES];
unsigned char *m_pFileBuf;
unsigned char *m_pFileBuf_tmp;
unsigned char* m_pFileBuf_tmp_old; //used for realloc
/**
* 初始化并连接到服务器
*
* @param url 服务器上对应webapp的地址
*
* @成功则返回1 , 失败则返回0
*/
int RTMP264_Connect(const char* url)
{
nalhead_pos=0;
m_nFileBufSize=BUFFER_SIZE;
m_pFileBuf=(unsigned char*)malloc(BUFFER_SIZE);
m_pFileBuf_tmp=(unsigned char*)malloc(BUFFER_SIZE);
m_pRtmp = RTMP_Alloc();
RTMP_Init(m_pRtmp);
/*设置URL*/
if (RTMP_SetupURL(m_pRtmp,(char*)url) == FALSE)
{
RTMP_Free(m_pRtmp);
return false;
}
/*设置可写,即发布流,这个函数必须在连接前使用,否则无效*/
RTMP_EnableWrite(m_pRtmp);
/*连接服务器*/
if (RTMP_Connect(m_pRtmp, NULL) == FALSE)
{
RTMP_Free(m_pRtmp);
return false;
}
/*连接流*/
if (RTMP_ConnectStream(m_pRtmp,0) == FALSE)
{
RTMP_Close(m_pRtmp);
RTMP_Free(m_pRtmp);
return false;
}
return true;
}
/**
* 断开连接,释放相关的资源。
*
*/
void RTMP264_Close()
{
if(m_pRtmp)
{
RTMP_Close(m_pRtmp);
RTMP_Free(m_pRtmp);
m_pRtmp = NULL;
}
if (m_pFileBuf != NULL)
{
free(m_pFileBuf);
}
if (m_pFileBuf_tmp != NULL)
{
free(m_pFileBuf_tmp);
}
}
/**
* 发送RTMP数据包
*
* @param nPacketType 数据类型
* @param data 存储数据内容
* @param size 数据大小
* @param nTimestamp 当前包的时间戳
*
* @成功则返回 1 , 失败则返回一个小于0的数
*/
int SendPacket(unsigned int nPacketType,unsigned char *data,unsigned int size,unsigned int nTimestamp)
{
if(m_pRtmp == NULL) return -1;
RTMPPacket* packet;
/*分配包内存和初始化,len为包体长度*/
packet = (RTMPPacket *)m_pBuff;
/*包体内存*/
packet->m_body = (char *)packet + RTMP_HEAD_SIZE;
packet->m_nBodySize = size;
//memcpy(packet->m_bod