|
|
@ -38,42 +38,41 @@ void VideoStream::setVideoEncInfo(int width, int height, int fps, int bitrate) { |
|
|
|
DELETE(pic_in); |
|
|
|
DELETE(pic_in); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//打开x264编码器
|
|
|
|
//setting x264 params
|
|
|
|
//x264编码器的属性
|
|
|
|
|
|
|
|
x264_param_t param; |
|
|
|
x264_param_t param; |
|
|
|
x264_param_default_preset(¶m, "ultrafast", "zerolatency"); |
|
|
|
x264_param_default_preset(¶m, "ultrafast", "zerolatency"); |
|
|
|
param.i_level_idc = 32; |
|
|
|
param.i_level_idc = 32; |
|
|
|
//输入数据格式
|
|
|
|
//input format
|
|
|
|
param.i_csp = X264_CSP_I420; |
|
|
|
param.i_csp = X264_CSP_I420; |
|
|
|
param.i_width = width; |
|
|
|
param.i_width = width; |
|
|
|
param.i_height = height; |
|
|
|
param.i_height = height; |
|
|
|
//无b帧
|
|
|
|
//no B frame
|
|
|
|
param.i_bframe = 0; |
|
|
|
param.i_bframe = 0; |
|
|
|
//参数i_rc_method表示码率控制,CQP(恒定质量),CRF(恒定码率),ABR(平均码率)
|
|
|
|
//i_rc_method:bitrate control, CQP(constant quality), CRF(constant bitrate), ABR(average bitrate)
|
|
|
|
param.rc.i_rc_method = X264_RC_ABR; |
|
|
|
param.rc.i_rc_method = X264_RC_ABR; |
|
|
|
//码率(比特率,单位Kbps)
|
|
|
|
//bitrate(Kbps)
|
|
|
|
param.rc.i_bitrate = bitrate / 1000; |
|
|
|
param.rc.i_bitrate = bitrate / 1000; |
|
|
|
//瞬时最大码率
|
|
|
|
//max bitrate
|
|
|
|
param.rc.i_vbv_max_bitrate = bitrate / 1000 * 1.2; |
|
|
|
param.rc.i_vbv_max_bitrate = bitrate / 1000 * 1.2; |
|
|
|
//设置了i_vbv_max_bitrate必须设置此参数,码率控制区大小,单位kbps
|
|
|
|
//unit:kbps
|
|
|
|
param.rc.i_vbv_buffer_size = bitrate / 1000; |
|
|
|
param.rc.i_vbv_buffer_size = bitrate / 1000; |
|
|
|
|
|
|
|
|
|
|
|
//帧率
|
|
|
|
//frame rate
|
|
|
|
param.i_fps_num = fps; |
|
|
|
param.i_fps_num = fps; |
|
|
|
param.i_fps_den = 1; |
|
|
|
param.i_fps_den = 1; |
|
|
|
param.i_timebase_den = param.i_fps_num; |
|
|
|
param.i_timebase_den = param.i_fps_num; |
|
|
|
param.i_timebase_num = param.i_fps_den; |
|
|
|
param.i_timebase_num = param.i_fps_den; |
|
|
|
//用fps而不是时间戳来计算帧间距离
|
|
|
|
//using fps
|
|
|
|
param.b_vfr_input = 0; |
|
|
|
param.b_vfr_input = 0; |
|
|
|
//帧距离(关键帧) 2s一个关键帧
|
|
|
|
//key frame interval(GOP)
|
|
|
|
param.i_keyint_max = fps * 2; |
|
|
|
param.i_keyint_max = fps * 2; |
|
|
|
//设置是让每个关键帧(I帧)都附带sps/pps
|
|
|
|
//each key frame attaches sps/pps
|
|
|
|
param.b_repeat_headers = 1; |
|
|
|
param.b_repeat_headers = 1; |
|
|
|
//多线程
|
|
|
|
//thread number
|
|
|
|
param.i_threads = 1; |
|
|
|
param.i_threads = 1; |
|
|
|
|
|
|
|
|
|
|
|
x264_param_apply_profile(¶m, "baseline"); |
|
|
|
x264_param_apply_profile(¶m, "baseline"); |
|
|
|
//打开编码器
|
|
|
|
//open encoder
|
|
|
|
videoCodec = x264_encoder_open(¶m); |
|
|
|
videoCodec = x264_encoder_open(¶m); |
|
|
|
pic_in = new x264_picture_t; |
|
|
|
pic_in = new x264_picture_t; |
|
|
|
x264_picture_alloc(pic_in, X264_CSP_I420, width, height); |
|
|
|
x264_picture_alloc(pic_in, X264_CSP_I420, width, height); |
|
|
@ -86,10 +85,10 @@ void VideoStream::setVideoCallback(VideoCallback videoCallback) { |
|
|
|
|
|
|
|
|
|
|
|
void VideoStream::encodeData(int8_t *data) { |
|
|
|
void VideoStream::encodeData(int8_t *data) { |
|
|
|
pthread_mutex_lock(&mutex); |
|
|
|
pthread_mutex_lock(&mutex); |
|
|
|
//y数据
|
|
|
|
//y
|
|
|
|
memcpy(pic_in->img.plane[0], data, ySize); |
|
|
|
memcpy(pic_in->img.plane[0], data, ySize); |
|
|
|
for (int i = 0; i < uvSize; ++i) { |
|
|
|
for (int i = 0; i < uvSize; ++i) { |
|
|
|
//u数据
|
|
|
|
//uv
|
|
|
|
*(pic_in->img.plane[1] + i) = *(data + ySize + i * 2 + 1); |
|
|
|
*(pic_in->img.plane[1] + i) = *(data + ySize + i * 2 + 1); |
|
|
|
*(pic_in->img.plane[2] + i) = *(data + ySize + i * 2); |
|
|
|
*(pic_in->img.plane[2] + i) = *(data + ySize + i * 2); |
|
|
|
} |
|
|
|
} |
|
|
@ -120,10 +119,9 @@ void VideoStream::encodeData(int8_t *data) { |
|
|
|
void VideoStream::encodeDataNew(int8_t *y_plane, int8_t *u_plane, int8_t *v_plane) { |
|
|
|
void VideoStream::encodeDataNew(int8_t *y_plane, int8_t *u_plane, int8_t *v_plane) { |
|
|
|
pthread_mutex_lock(&mutex); |
|
|
|
pthread_mutex_lock(&mutex); |
|
|
|
|
|
|
|
|
|
|
|
//直接拷贝
|
|
|
|
|
|
|
|
memcpy(pic_in->img.plane[0], y_plane, (size_t) ySize); |
|
|
|
memcpy(pic_in->img.plane[0], y_plane, (size_t) ySize); |
|
|
|
memcpy(pic_in->img.plane[1], u_plane, (size_t) ySize/4); |
|
|
|
memcpy(pic_in->img.plane[1], u_plane, (size_t) ySize / 4); |
|
|
|
memcpy(pic_in->img.plane[2], v_plane, (size_t) ySize/4); |
|
|
|
memcpy(pic_in->img.plane[2], v_plane, (size_t) ySize / 4); |
|
|
|
|
|
|
|
|
|
|
|
x264_nal_t *pp_nal; |
|
|
|
x264_nal_t *pp_nal; |
|
|
|
int pi_nal; |
|
|
|
int pi_nal; |
|
|
@ -153,17 +151,16 @@ void VideoStream::sendSpsPps(uint8_t *sps, uint8_t *pps, int sps_len, int pps_le |
|
|
|
RTMPPacket *packet = new RTMPPacket; |
|
|
|
RTMPPacket *packet = new RTMPPacket; |
|
|
|
RTMPPacket_Alloc(packet, bodySize); |
|
|
|
RTMPPacket_Alloc(packet, bodySize); |
|
|
|
int i = 0; |
|
|
|
int i = 0; |
|
|
|
//固定头
|
|
|
|
//start code
|
|
|
|
packet->m_body[i++] = 0x17; |
|
|
|
packet->m_body[i++] = 0x17; |
|
|
|
//类型
|
|
|
|
//type
|
|
|
|
packet->m_body[i++] = 0x00; |
|
|
|
packet->m_body[i++] = 0x00; |
|
|
|
packet->m_body[i++] = 0x00; |
|
|
|
packet->m_body[i++] = 0x00; |
|
|
|
packet->m_body[i++] = 0x00; |
|
|
|
packet->m_body[i++] = 0x00; |
|
|
|
packet->m_body[i++] = 0x00; |
|
|
|
packet->m_body[i++] = 0x00; |
|
|
|
|
|
|
|
|
|
|
|
//版本
|
|
|
|
//version
|
|
|
|
packet->m_body[i++] = 0x01; |
|
|
|
packet->m_body[i++] = 0x01; |
|
|
|
//编码规格
|
|
|
|
|
|
|
|
packet->m_body[i++] = sps[1]; |
|
|
|
packet->m_body[i++] = sps[1]; |
|
|
|
packet->m_body[i++] = sps[2]; |
|
|
|
packet->m_body[i++] = sps[2]; |
|
|
|
packet->m_body[i++] = sps[3]; |
|
|
|
packet->m_body[i++] = sps[3]; |
|
|
@ -171,7 +168,7 @@ void VideoStream::sendSpsPps(uint8_t *sps, uint8_t *pps, int sps_len, int pps_le |
|
|
|
|
|
|
|
|
|
|
|
//sps
|
|
|
|
//sps
|
|
|
|
packet->m_body[i++] = 0xE1; |
|
|
|
packet->m_body[i++] = 0xE1; |
|
|
|
//sps长度
|
|
|
|
//sps len
|
|
|
|
packet->m_body[i++] = (sps_len >> 8) & 0xff; |
|
|
|
packet->m_body[i++] = (sps_len >> 8) & 0xff; |
|
|
|
packet->m_body[i++] = sps_len & 0xff; |
|
|
|
packet->m_body[i++] = sps_len & 0xff; |
|
|
|
memcpy(&packet->m_body[i], sps, sps_len); |
|
|
|
memcpy(&packet->m_body[i], sps, sps_len); |
|
|
@ -183,13 +180,12 @@ void VideoStream::sendSpsPps(uint8_t *sps, uint8_t *pps, int sps_len, int pps_le |
|
|
|
packet->m_body[i++] = (pps_len) & 0xff; |
|
|
|
packet->m_body[i++] = (pps_len) & 0xff; |
|
|
|
memcpy(&packet->m_body[i], pps, pps_len); |
|
|
|
memcpy(&packet->m_body[i], pps, pps_len); |
|
|
|
|
|
|
|
|
|
|
|
//视频
|
|
|
|
//video
|
|
|
|
packet->m_packetType = RTMP_PACKET_TYPE_VIDEO; |
|
|
|
packet->m_packetType = RTMP_PACKET_TYPE_VIDEO; |
|
|
|
packet->m_nBodySize = bodySize; |
|
|
|
packet->m_nBodySize = bodySize; |
|
|
|
packet->m_nChannel = 10; |
|
|
|
packet->m_nChannel = 10; |
|
|
|
//sps pps没有时间戳
|
|
|
|
//sps and pps no timestamp
|
|
|
|
packet->m_nTimeStamp = 0; |
|
|
|
packet->m_nTimeStamp = 0; |
|
|
|
//不使用绝对时间
|
|
|
|
|
|
|
|
packet->m_hasAbsTimestamp = 0; |
|
|
|
packet->m_hasAbsTimestamp = 0; |
|
|
|
packet->m_headerType = RTMP_PACKET_SIZE_MEDIUM; |
|
|
|
packet->m_headerType = RTMP_PACKET_SIZE_MEDIUM; |
|
|
|
|
|
|
|
|
|
|
@ -206,23 +202,22 @@ void VideoStream::sendFrame(int type, uint8_t *payload, int i_payload) { |
|
|
|
} |
|
|
|
} |
|
|
|
int bodySize = 9 + i_payload; |
|
|
|
int bodySize = 9 + i_payload; |
|
|
|
RTMPPacket *packet = new RTMPPacket; |
|
|
|
RTMPPacket *packet = new RTMPPacket; |
|
|
|
//
|
|
|
|
|
|
|
|
RTMPPacket_Alloc(packet, bodySize); |
|
|
|
RTMPPacket_Alloc(packet, bodySize); |
|
|
|
|
|
|
|
|
|
|
|
packet->m_body[0] = 0x27; |
|
|
|
packet->m_body[0] = 0x27; |
|
|
|
if(type == NAL_SLICE_IDR){ |
|
|
|
if (type == NAL_SLICE_IDR) { |
|
|
|
packet->m_body[0] = 0x17; |
|
|
|
packet->m_body[0] = 0x17; |
|
|
|
if (DEBUG) { |
|
|
|
if (DEBUG) { |
|
|
|
LOGI("IDR key frame"); |
|
|
|
LOGI("IDR key frame"); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
//类型
|
|
|
|
//packet type
|
|
|
|
packet->m_body[1] = 0x01; |
|
|
|
packet->m_body[1] = 0x01; |
|
|
|
//时间戳
|
|
|
|
//timestamp
|
|
|
|
packet->m_body[2] = 0x00; |
|
|
|
packet->m_body[2] = 0x00; |
|
|
|
packet->m_body[3] = 0x00; |
|
|
|
packet->m_body[3] = 0x00; |
|
|
|
packet->m_body[4] = 0x00; |
|
|
|
packet->m_body[4] = 0x00; |
|
|
|
//数据长度 int 4个字节
|
|
|
|
//packet len
|
|
|
|
packet->m_body[5] = (i_payload >> 24) & 0xff; |
|
|
|
packet->m_body[5] = (i_payload >> 24) & 0xff; |
|
|
|
packet->m_body[6] = (i_payload >> 16) & 0xff; |
|
|
|
packet->m_body[6] = (i_payload >> 16) & 0xff; |
|
|
|
packet->m_body[7] = (i_payload >> 8) & 0xff; |
|
|
|
packet->m_body[7] = (i_payload >> 8) & 0xff; |
|
|
|