Created
November 24, 2012 22:45
-
-
Save eugenehp/4141707 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // demo.cpp : 定义控制台应用程序的入口点。 | |
| // | |
| #include "stdafx.h" | |
| #include <MqOaI.h> | |
| extern "C" | |
| { | |
| #include "../../common/common.h" | |
| #include "../../common/cpu.h"" | |
| #include "../../x264.h" | |
| #include "../../encoder/set.h" | |
| } | |
| #include "librtmp/rtmp_sys.h" | |
| #include "librtmp/log.h" | |
| #include "librtmp/amf.h" | |
| #include "CameraDS.h" | |
| void ConvertYCbCr2BGR(unsigned char *pYUV,unsigned char *pBGR,int iWidth,int iHeight); | |
| void ConvertRGB2YUV(int w,int h,unsigned char *bmp,unsigned char *yuv); | |
| int InitSockets() | |
| { | |
| #ifdef WIN32 | |
| WORD version; | |
| WSADATA wsaData; | |
| version = MAKEWORD(1, 1); | |
| return (WSAStartup(version, &wsaData) == 0); | |
| #else | |
| return TRUE; | |
| #endif | |
| } | |
| inline void CleanupSockets() | |
| { | |
| #ifdef WIN32 | |
| WSACleanup(); | |
| #endif | |
| } | |
| #define HEX2BIN(a) (((a)&0x40)?((a)&0xf)+9:((a)&0xf)) | |
| int hex2bin(char *str, char **hex) | |
| { | |
| char *ptr; | |
| int i, l = strlen(str); | |
| if (l & 1) | |
| return 0; | |
| *hex = (char *)malloc(l/2); | |
| ptr = *hex; | |
| if (!ptr) | |
| return 0; | |
| for (i=0; i<l; i+=2) | |
| *ptr++ = (HEX2BIN(str[i]) << 4) | HEX2BIN(str[i+1]); | |
| return l/2; | |
| } | |
| 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; | |
| } | |
| int main(int argc, char * argv[]) | |
| { | |
| if (argc<2) | |
| { | |
| RTMP_LogPrintf("RTMP_URL IS NULL!!!/n"); | |
| //return -1; | |
| } | |
| if (!InitSockets()) | |
| { | |
| RTMP_LogPrintf("InitSockets Error!/n"); | |
| return -1; | |
| } | |
| RTMP_LogPrintf("InitSockets!/n"); | |
| CoInitialize(NULL); | |
| CCameraDS camera; | |
| if (!camera.OpenCamera(0,320,240,false)) | |
| { | |
| RTMP_LogPrintf("Open Camera Error/n"); | |
| return -1; | |
| } | |
| int nHeight=camera.GetHeight(); | |
| int nWidth=camera.GetWidth(); | |
| unsigned char * szRGBBuffer=new unsigned char[nHeight*nWidth * 3]; | |
| RTMP_LogPrintf("Camera Open Scuess! Picture Size[%2dx%d]/n",nWidth,nHeight); | |
| RTMP_debuglevel = RTMP_LOGINFO; | |
| RTMP *r; | |
| //char uri[]="rtmp://127.0.0.1/live/test"; | |
| //char uri[]="rtmp://192.199.15.223/live/test"; | |
| //char uri[]="rtmp://221.9.244.4/live/jltv"; | |
| //char uri[]="rtmp://192.199.15.223/oflaDemo/red5StreamDemo"; | |
| //char uri[]="rtmp://192.199.15.151/live/test"; | |
| char uri[]="rtmp://127.0.0.1/live/zzj"; | |
| r= RTMP_Alloc(); | |
| RTMP_Init(r); | |
| RTMP_SetupURL(r, (char*)uri); | |
| RTMP_EnableWrite(r); | |
| RTMP_Connect(r, NULL); | |
| RTMP_ConnectStream(r,0); | |
| unsigned char szNalBuffer[1024*32]; | |
| unsigned char szBodyBuffer[1024*32]; | |
| x264_nal_t *p264Nal; | |
| int i264Nal; | |
| x264_param_t * p264Param; | |
| x264_picture_t * p264Pic; | |
| x264_t *p264Handle; | |
| p264Param = new x264_param_t(); | |
| p264Pic = new x264_picture_t(); | |
| memset(p264Pic,0,sizeof(x264_picture_t)); | |
| x264_param_default(p264Param); //set default param | |
| p264Param->i_threads=2; | |
| p264Param->i_width = nWidth; //set frame width | |
| p264Param->i_height = nHeight; //set frame height | |
| /*baseline level 1.1*/ | |
| p264Param->b_cabac =0; | |
| p264Param->i_bframe =0; | |
| p264Param->b_interlaced=0; | |
| p264Param->rc.i_rc_method=X264_RC_ABR;//X264_RC_CQP | |
| p264Param->i_level_idc=21; | |
| p264Param->rc.i_bitrate=200; | |
| p264Param->i_fps_num=30; | |
| p264Param->i_keyint_max=p264Param->i_fps_num*3; | |
| if((p264Handle = x264_encoder_open(p264Param)) == NULL) | |
| { | |
| fprintf( stderr, "x264_encoder_open failed/n" ); | |
| return -2; | |
| } | |
| bs_t bs={0}; | |
| x264_picture_alloc(p264Pic, X264_CSP_YV12, p264Param->i_width, p264Param->i_height); | |
| p264Pic->i_type = X264_TYPE_AUTO; | |
| x264_picture_t pic_out; | |
| RTMPPacket packet={0}; | |
| memset(&packet,0,sizeof(RTMPPacket)); | |
| packet.m_nChannel = 0x04; | |
| packet.m_headerType = RTMP_PACKET_SIZE_LARGE; | |
| packet.m_nTimeStamp = 0; | |
| packet.m_nInfoField2 = r->m_stream_id; | |
| packet.m_hasAbsTimestamp = 0; | |
| packet.m_body =(char *) szBodyBuffer; | |
| char * szTmp=(char *)szBodyBuffer; | |
| packet.m_packetType = RTMP_PACKET_TYPE_INFO; | |
| szTmp=put_byte(szTmp, AMF_STRING ); | |
| szTmp=put_amf_string(szTmp, "@setDataFrame" ); | |
| szTmp=put_byte(szTmp, AMF_STRING ); | |
| szTmp=put_amf_string(szTmp, "onMetaData" ); | |
| szTmp=put_byte(szTmp, AMF_OBJECT ); | |
| szTmp=put_amf_string( szTmp, "author" ); | |
| szTmp=put_byte(szTmp, AMF_STRING ); | |
| szTmp=put_amf_string( szTmp, "" ); | |
| szTmp=put_amf_string( szTmp, "copyright" ); | |
| szTmp=put_byte(szTmp, AMF_STRING ); | |
| szTmp=put_amf_string( szTmp, "" ); | |
| szTmp=put_amf_string( szTmp, "description" ); | |
| szTmp=put_byte(szTmp, AMF_STRING ); | |
| szTmp=put_amf_string( szTmp, "" ); | |
| szTmp=put_amf_string( szTmp, "keywords" ); | |
| szTmp=put_byte(szTmp, AMF_STRING ); | |
| szTmp=put_amf_string( szTmp, "" ); | |
| szTmp=put_amf_string( szTmp, "rating" ); | |
| szTmp=put_byte(szTmp, AMF_STRING ); | |
| szTmp=put_amf_string( szTmp, "" ); | |
| szTmp=put_amf_string( szTmp, "presetname" ); | |
| szTmp=put_byte(szTmp, AMF_STRING ); | |
| szTmp=put_amf_string( szTmp, "Custom" ); | |
| szTmp=put_amf_string( szTmp, "width" ); | |
| szTmp=put_amf_double( szTmp, p264Param->i_width ); | |
| szTmp=put_amf_string( szTmp, "width" ); | |
| szTmp=put_amf_double( szTmp, p264Param->i_width ); | |
| szTmp=put_amf_string( szTmp, "height" ); | |
| szTmp=put_amf_double( szTmp, p264Param->i_height ); | |
| szTmp=put_amf_string( szTmp, "framerate" ); | |
| szTmp=put_amf_double( szTmp, (double)p264Param->i_fps_num / p264Param->i_fps_den ); | |
| szTmp=put_amf_string( szTmp, "videocodecid" ); | |
| szTmp=put_byte(szTmp, AMF_STRING ); | |
| szTmp=put_amf_string( szTmp, "avc1" ); | |
| szTmp=put_amf_string( szTmp, "videodatarate" ); | |
| szTmp=put_amf_double( szTmp, p264Param->rc.i_bitrate ); | |
| szTmp=put_amf_string( szTmp, "avclevel" ); | |
| szTmp=put_amf_double( szTmp, p264Param->i_level_idc ); | |
| szTmp=put_amf_string( szTmp, "avcprofile" ); | |
| szTmp=put_amf_double( szTmp, 0x42 ); | |
| szTmp=put_amf_string( szTmp, "videokeyframe_frequency" ); | |
| szTmp=put_amf_double( szTmp, 3 ); | |
| szTmp=put_amf_string( szTmp, "" ); | |
| szTmp=put_byte( szTmp, AMF_OBJECT_END ); | |
| packet.m_nBodySize=szTmp-(char *)szBodyBuffer; | |
| RTMP_SendPacket(r,&packet,1); | |
| packet.m_packetType = RTMP_PACKET_TYPE_VIDEO; /* VIDEO */ | |
| szBodyBuffer[ 0]=0x17; | |
| szBodyBuffer[ 1]=0x00; | |
| szBodyBuffer[ 2]=0x00; | |
| szBodyBuffer[ 3]=0x00; | |
| szBodyBuffer[ 4]=0x00; | |
| szBodyBuffer[ 5]=0x01; | |
| szBodyBuffer[ 6]=0x42; | |
| szBodyBuffer[ 7]=0xC0; | |
| szBodyBuffer[ 8]=0x15; | |
| szBodyBuffer[ 9]=0x03; | |
| szBodyBuffer[10]=0x01; | |
| szTmp=(char *)szBodyBuffer+11; | |
| short slen=0; | |
| bs_init(&bs,szNalBuffer,16);//初始话bs | |
| x264_sps_write(&bs, p264Handle->sps);//读取编码器的SPS | |
| slen=bs.p-bs.p_start+1;//spslen(short) | |
| slen=htons(slen); | |
| memcpy(szTmp,&slen,sizeof(short)); | |
| szTmp+=sizeof(short); | |
| *szTmp=0x67; | |
| szTmp+=1; | |
| memcpy(szTmp,bs.p_start,bs.p-bs.p_start); | |
| szTmp+=bs.p-bs.p_start; | |
| *szTmp=0x01; | |
| szTmp+=1; | |
| bs_init(&bs,szNalBuffer,16);//初始话bs | |
| x264_pps_write(&bs, p264Handle->pps);//读取编码器的PPS | |
| slen=bs.p-bs.p_start+1;//spslen(short) | |
| slen=htons(slen); | |
| memcpy(szTmp,&slen,sizeof(short)); | |
| szTmp+=sizeof(short); | |
| *szTmp=0x68; | |
| szTmp+=1; | |
| memcpy(szTmp,bs.p_start,bs.p-bs.p_start); | |
| szTmp+=bs.p-bs.p_start; | |
| packet.m_nBodySize=szTmp-(char *)szBodyBuffer; | |
| RTMP_SendPacket(r,&packet,0); | |
| unsigned int nTimes=0; | |
| unsigned int oldTick=GetTickCount(); | |
| unsigned int newTick=0; | |
| packet.m_nTimeStamp=0; | |
| while(true) | |
| { | |
| szBodyBuffer[ 0]=0x17; | |
| szBodyBuffer[ 1]=0x01; | |
| szBodyBuffer[ 2]=0x00; | |
| szBodyBuffer[ 3]=0x00; | |
| szBodyBuffer[ 4]=0x42; | |
| unsigned char * szTmp=szBodyBuffer+5; | |
| unsigned char * pNal=szNalBuffer; | |
| nTimes++; | |
| int nFramsInPack=0; | |
| while(true) | |
| { | |
| nFramsInPack++; | |
| unsigned char * pCameraBuf = camera.QueryFrame(); | |
| if (!pCameraBuf) | |
| { | |
| return -1; | |
| } | |
| for(int ii=0;ii<nHeight;ii++) | |
| { | |
| memcpy(szRGBBuffer+(nWidth*3)*(nHeight-ii-1),pCameraBuf+(nWidth*3)*ii,nWidth*3); | |
| //memcpy(pCameraBuf+nWidth*(nHeight-ii-1),pCameraBuf+nWidth*ii,nWidth*3); | |
| //memcpy(szLineBuffer,pCameraBuf+nWidth*(nHeight-ii-1),nWidth*3); | |
| } | |
| ConvertRGB2YUV(nWidth,nHeight,szRGBBuffer,p264Pic->img.plane[0]); | |
| //memcpy(p264Pic->img.plane[0],szNalBuffer,nWidth*nHeight); | |
| //memcpy(p264Pic->img.plane[1],szNalBuffer+nWidth*nHeight,nWidth*nHeight/4); | |
| //memcpy(p264Pic->img.plane[2],szNalBuffer+nWidth*nHeight*5/4,nWidth*nHeight/4); | |
| /* | |
| int nCount; | |
| nCount=fread(p264Pic->img.plane[0],1,176*144,yuv); | |
| if (nCount<176*144) | |
| { | |
| fseek(yuv,SEEK_SET,0); | |
| continue; | |
| } | |
| nCount=fread(p264Pic->img.plane[1],1,176*144/4,yuv); | |
| if (nCount<176*144/4) | |
| { | |
| fseek(yuv,SEEK_SET,0); | |
| continue; | |
| } | |
| nCount=fread(p264Pic->img.plane[2],1,176*144/4,yuv); | |
| if (nCount<176*144/4) | |
| { | |
| fseek(yuv,SEEK_SET,0); | |
| continue; | |
| } | |
| */ | |
| if( x264_encoder_encode( p264Handle, &p264Nal, &i264Nal, p264Pic ,&pic_out) < 0 ) | |
| { | |
| fprintf( stderr, "x264_encoder_encode failed/n" ); | |
| } | |
| for( int i = 0; i < i264Nal; i++ ) | |
| { | |
| int i_size; | |
| int i_data; | |
| i_data = 1024*32; | |
| if( ( i_size = x264_nal_encode( pNal, &i_data, 1, &p264Nal[i] ) ) > 0 ) | |
| { | |
| if ((pNal[4]&0x60)==0) | |
| { | |
| continue; | |
| } | |
| if (pNal[4]==0x67) | |
| { | |
| continue; | |
| } | |
| if (pNal[4]==0x68) | |
| { | |
| continue; | |
| } | |
| memmove(pNal,pNal+4,i_size-4); | |
| pNal+=i_size-4; | |
| } | |
| else if( i_size < 0 ) | |
| { | |
| fprintf( stderr,"need to increase buffer size (size=%d)/n", -i_size ); | |
| } | |
| } | |
| unsigned int nSize=pNal-szNalBuffer; | |
| packet.m_nBodySize=nSize+9; | |
| if (i264Nal>1) | |
| { | |
| szBodyBuffer[ 0]=0x17; | |
| } | |
| else | |
| { | |
| szBodyBuffer[ 0]=0x27; | |
| } | |
| put_be32((char *)szBodyBuffer+5,nSize); | |
| memcpy(szBodyBuffer+9,szNalBuffer,pNal-szNalBuffer); | |
| RTMP_SendPacket(r,&packet,0); | |
| Sleep(20); | |
| newTick=GetTickCount(); | |
| //RTMP_LogStatus("/rInfo NAUL Type:0x%02x size: %5d Tick:%03d %03d",szNalBuffer[0], nSize,33-nSleep,GetTickCount()-oldTick+nSleep); | |
| packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM; | |
| packet.m_nTimeStamp+=newTick-oldTick; | |
| oldTick=newTick; | |
| break; | |
| } | |
| } | |
| return 0; | |
| } |
Author
Author
//Thread
While (ThreadIsRunning && RTMP_IsConnected(r) && RTMP_ReadPacket(r, &packet))
{
if (RTMPPacket_IsReady(&packet))
{
if (!packet.m_nBodySize)
continue;
RTMP_ClientPacket(r, &packet); //This takes care of handling ping/other messages
RTMPPacket_Free(&packet);
}
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
translation from chinese: [24楼 sos_20101232011-10-09 23:35发表[回复]]
Can be introduced under a rough idea of what?
(1) X264 a YUV420 convert H264;
(2) According to the RTMP protocol, set the parameters LibRTMP control interface functions,
mainly to set the message header, message body, set the message type, packet length, data type video parameters ;
(3) NAL copied to a LibRtmp structure,
then with RTMP_SendPacket (r, & packet, 0);
contract to Wowza, Red5 can?