H264或HEVC及AAC音頻的PS流打包

1、使用libmpeg

使用libmpeg庫完成PS流格式封裝,對於GB28181音頻封裝修改libmepg代碼,使音頻不帶PS頭。該庫支持PS/TS流的封包及解包。

2、demo

《1》、封裝類

/* 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);
        }
    }

}

《2》、回調

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);
}

《3》、調用

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;
}

4、完整demo

3、參考

《0》、librtmp github地址
《1》、國標PS流打包和RTP發送代碼
《2》、攝像機源碼模擬器
《3》、流媒體-----PS流

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章