使用libmpeg库完成PS流格式封装,对于GB28181音频封装修改libmepg代码,使音频不带PS头。该库支持PS/TS流的封包及解包。
/* ps封装类 */
class ps_muxer_context
{
public:
ps_muxer_context(char* input_file);
~ps_muxer_context();
void ProcessLoop();
ps_muxer_t* ps;
char input[256];
char output[256];
int audio_id;
int video_id;
ff_rtmp_client receiver;
FILE* fp;
struct ps_muxer_func_t handler;
};
ps_muxer_context::ps_muxer_context(char* input_file)
{
memset(output, 0, 256);
memset(input, 0, 256);
snprintf(output, sizeof(output), "%s.ps", input_file);
snprintf(input, sizeof(input), "%s", input_file);
handler.alloc = ps_alloc;
handler.write = ps_write;
handler.free = ps_free;
fp = fopen(output, "wb");
ps = ps_muxer_create(&handler, this);
audio_id = ps_muxer_add_stream(ps, PSI_STREAM_AAC, NULL, 0);
video_id = ps_muxer_add_stream(ps, PSI_STREAM_H264, NULL, 0);
cout << "##### audio_id " << audio_id << " video_id " << video_id << endl;
receiver.rtmp_pull_open(input_file);
}
ps_muxer_context::~ps_muxer_context()
{
ps_muxer_destroy(ps);
fclose(fp);
}
void ps_muxer_context::ProcessLoop()
{
FrameInfo video;
FrameInfo audio;
int cnt = 25000; /* 处理15000帧 */
if(receiver.start_process())
{
cout << " start_process success " << endl;
int64_t current_video_pts = 0;
int64_t current_audio_pts = 0;
while(1)
{
--cnt;
if(cnt <= 0)
{
break;
}
int flags = MPEG_FLAG_H264_H265_WITH_AUD;
int64_t compare_tag = -1;
bool bwait = true;
if(receiver.GetAudioQueueSize() > 0)
{
bwait = false;
}
/* 粗略的音视频同步策略 */
if(!bwait)
{
compare_tag = current_video_pts - current_audio_pts; //compare fileDate
}
cout << "------------------- compare_tag " << compare_tag << endl;
if (compare_tag <= 0)
{
receiver.get_video_frame(video);
if(video.data && video.data_size > 0 )
{
int frame_type = H264_FRAME_NALU;
frame_type = H264_GetFrameType(video.data, video.data_size, 4);
if (frame_type == H264_FRAME_I || frame_type == H264_FRAME_SI)
{
flags |= MPEG_FLAG_IDR_FRAME;
}
else
{
frame_type = H264_GetFrameType(video.data, video.data_size, 3);
if (frame_type == H264_FRAME_I || frame_type == H264_FRAME_SI)
{
flags |= MPEG_FLAG_IDR_FRAME;
}
}
ps_muxer_input(ps, video_id, flags, video.time_stamp, video.time_stamp, video.data, video.data_size);
current_video_pts = video.time_stamp;
delete[] video.data;
video.data = NULL;
}
}
else
{
receiver.get_audio_frame(audio);
if(audio.data && audio.data_size > 0 )
{
flags = MPEG_FLAG_H264_H265_WITH_AUD;
ps_muxer_input(ps, audio_id, flags, audio.time_stamp, audio.time_stamp, audio.data, audio.data_size);
current_audio_pts = audio.time_stamp;
delete[] audio.data;
audio.data = NULL;
}
}
usleep(200);
}
}
}
static void* ps_alloc(void* /*param*/, size_t bytes)
{
static char s_buffer[2 * 1024 * 1024];
assert(bytes <= sizeof(s_buffer));
return s_buffer;
}
static void ps_free(void* /*param*/, void* /*packet*/)
{
return;
}
static void ps_write(void* param, int stream, void* packet, size_t bytes)
{
printf("stream = %d \n", stream);
ps_muxer_context* handle = (ps_muxer_context*) param;
fwrite(packet, bytes, 1, handle->fp);
fflush(handle->fp);
}
int main()
{
char* file = "../cus_ies.mp4";
ps_muxer_context ps_muxer(file);
ps_muxer.ProcessLoop();
//printf("Success\n");
char output[256]={'\0'};
char* in_file = "../PsMux.mpeg";
snprintf(output, sizeof(output), "%s.ps", file);
//mpeg_ps_dec_test(in_file);
getchar();
getchar();
getchar();
return 0;
}
《0》、librtmp github地址
《1》、国标PS流打包和RTP发送代码
《2》、摄像机源码模拟器
《3》、流媒体-----PS流